home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wvnsc926 / rcs / wvcoding.c < prev    next >
C/C++ Source or Header  |  1994-09-21  |  92KB  |  3,363 lines

  1. head     1.12;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.12
  10. date     94.09.18.22.44.20;  author jcooper;  state Exp;
  11. branches ;
  12. next     1.11;
  13.  
  14. 1.11
  15. date     94.09.16.00.58.48;  author jcooper;  state Exp;
  16. branches ;
  17. next     1.10;
  18.  
  19. 1.10
  20. date     94.08.24.18.00.29;  author jcooper;  state Exp;
  21. branches ;
  22. next     1.9;
  23.  
  24. 1.9
  25. date     94.08.11.21.03.19;  author rushing;  state Exp;
  26. branches ;
  27. next     1.8;
  28.  
  29. 1.8
  30. date     94.08.11.20.16.25;  author rushing;  state Exp;
  31. branches ;
  32. next     1.7;
  33.  
  34. 1.7
  35. date     94.08.11.00.09.17;  author jcooper;  state Exp;
  36. branches ;
  37. next     1.6;
  38.  
  39. 1.6
  40. date     94.07.25.20.05.13;  author jcooper;  state Exp;
  41. branches ;
  42. next     1.5;
  43.  
  44. 1.5
  45. date     94.05.23.18.36.00;  author jcooper;  state Exp;
  46. branches ;
  47. next     1.4;
  48.  
  49. 1.4
  50. date     94.03.01.19.14.22;  author rushing;  state Exp;
  51. branches ;
  52. next     1.3;
  53.  
  54. 1.3
  55. date     94.02.24.21.28.04;  author jcoop;  state Exp;
  56. branches ;
  57. next     1.2;
  58.  
  59. 1.2
  60. date     94.02.09.18.01.08;  author cnolan;  state Exp;
  61. branches ;
  62. next     1.1;
  63.  
  64. 1.1
  65. date     94.01.18.09.54.20;  author jcoop;  state Exp;
  66. branches ;
  67. next     ;
  68.  
  69.  
  70. desc
  71. @jcoop's en/decoding routines
  72. @
  73.  
  74.  
  75. 1.12
  76. log
  77. @Better handling of status windows, using IsBusy flag, etc
  78. @
  79. text
  80. @/********************************************************************
  81.  *                                                                  *
  82.  *  MODULE    :  WVCODING.C                                         *
  83.  *                                                                  *
  84.  *  PURPOSE   : This file contains functions for en/decoding files  *
  85.  *                                                                  *
  86.  *  ENTRY POINTS:                                                   *
  87.  *            DecodeInit  - initializes decoding resources        *
  88.  *        DecodeDone  - frees decoding resources              *
  89.  *        InitCoded   - initializes a coded block             * 
  90.  *                  called for each new art to decode     *
  91.  *        DecodeLine  - Main decoding engine.  Called once    *
  92.  *                  for each input line                   *
  93.  *        DecodeFile  - Uses file instead of comm input as a  *
  94.  *                     line provider to the decoding engine  *
  95.  *        DecodeDoc   - Uses a Doc instead of comm input as a *
  96.  *                     line provider to the decoding engine  *
  97.  *    CompleteThisDecode  - Called at end of each article - adds  *
  98.  *                  block to appropriate decode thread,   *
  99.  *                  writes to disk if possible, etc       *
  100.  *                  Encode  - Encodes a file into a text block      *
  101.  *            EncodeToFile  - Calls Encode, then writes block to    * 
  102.  *                            an output file                        *
  103.  *                                                                  *
  104.  *  NOTES:                                                          *
  105.  *    Both the max # of batched decode files and the max #        * 
  106.  *    threads per file are fixed.  This should be made dynamic    *
  107.  *    at some point I guess.                                      *
  108.  *                                                                  *
  109.  * Author: John S. Cooper (jcooper@@netcom.com)                      *
  110.  *   Date: Sept 13, 1993                                            *
  111.  *                                                                  *
  112.  * Let me know if you like this code, or if you re-use any piece of *
  113.  * it. I'm just curious to know what people think.                  *
  114.  ********************************************************************/
  115. /* 
  116.  * $Id: wvcoding.c 1.11 1994/09/16 00:58:48 jcooper Exp $
  117.  * $Log: wvcoding.c $
  118.  * Revision 1.11  1994/09/16  00:58:48  jcooper
  119.  * new coding-status window style.  optimized info-header parser.
  120.  * general cleanup for 92.6
  121.  * 
  122.  * Revision 1.10  1994/08/24  18:00:29  jcooper
  123.  * misc encoding/decoding changes
  124.  *
  125.  * Revision 1.9  1994/08/11  21:03:19  rushing
  126.  * FindExecutable fix for NT
  127.  *
  128.  * Revision 1.8  1994/08/11  20:16:25  rushing
  129.  * bug fix
  130.  *
  131.  * Revision 1.6  1994/07/25  20:05:13  jcooper
  132.  * execution of decoded files
  133.  *
  134.  * Revision 1.5  1994/05/23  18:36:00  jcooper
  135.  * new attach code, session [dis]connect
  136.  *
  137.  * Revision 1.4  1994/03/01  19:14:22  rushing
  138.  * ifdef'd the DEBUG info
  139.  *
  140.  * Revision 1.3  1994/02/24  21:28:04  jcoop
  141.  * jcoop changes.
  142.  *
  143.  * Revision 1.2  1994/02/09  18:01:08  cnolan
  144.  * cnolan 90.2 changes
  145.  *
  146.  * Revision 1.1  1994/01/18  09:54:20  jcoop
  147.  * Initial revision
  148.  *
  149.  */ 
  150. #include <windows.h>
  151. #include <windowsx.h>
  152. #include "wvglob.h"
  153. #include "winvn.h"
  154. #pragma hdrstop
  155. #include <string.h>
  156. #include <stdio.h>
  157. #include <stdlib.h>
  158. #include <ctype.h>        /* for isspace, isalnum, etc */
  159.  
  160. #ifdef _DEBUG
  161. #define DEBUG_MAP
  162. #define DEBUG_MEM
  163. #define DEBUG_DECODE
  164. #endif
  165.  
  166. #define LOW        1    // sequence confidence levels
  167. #define HIGH            2
  168. #define UNUSED        127    // unused mapping slots
  169.  
  170. #define END_BLOCK    2
  171. #define CODE_LINE_LEN    45    
  172. /*
  173.  * Globals for this func
  174.  */
  175. char
  176.     xxTable[CODINGTABLESIZE] = "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  177. char
  178.     uuTable[CODINGTABLESIZE] = "`!\"#$%&'()*+,-./0123456789:;<=>?@@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
  179. char
  180.     base64Table[CODINGTABLESIZE] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  181. char    *codingTable;
  182. char     customTable[CODINGTABLESIZE];
  183.  
  184. TypDecodeThread *threadList[MAX_DECODE_THREADS];
  185. int    numDecodeThreads;        // number of active decode threads
  186. int    currentDecodeThread;
  187. int    numDumbDecoded;
  188. BOOL    bossanovaMIME;                  // = TRUE if found MIME Version header
  189. int      thisNumBlocks;             // MIME vars for current block
  190. char     thisContentType[80];
  191. char    thisContentDesc[MAXINTERNALLINE];
  192. char    thisBoundary[MAXINTERNALLINE];
  193. int    thisContentEncoding, prevContentEncoding;
  194. char     prevBlockIdent[MAXFILENAME];
  195. /*
  196.  * Private functions
  197.  */
  198. int     EncodeLine (unsigned char *outLine, unsigned char *line, int start, int num);
  199. void    EncodeUnit (unsigned char *out, unsigned char *in, int num);
  200. int    GetThreadByName (char *name);
  201. int    AddToThreadList ();
  202. void     DestroyThread (int num);
  203. void    DestroyCodedBlock (TypCoded **thisCoded);
  204. void    InsertBlockInThread (int num, TypCoded *thisBlock, int index);
  205. void    DeleteBlockFromThread (int num, int index);
  206. BOOL    WriteDecodeThread(int num);
  207. BOOL    WriteBlockToFile(int num, TypCoded *thisDecode);
  208. BOOL    WriteTopBlockToFile (int num, int *endFlag);
  209. BOOL    AddDataToBlock (TypCoded *thisDecode, char *newData, unsigned int dataLen);
  210. void    ParseInfoLine (TypCoded *thisDecode, char *line, BOOL guessIdent);
  211. BOOL    ParseAppSpecificLine (TypCoded *thisDecode, char *line);
  212. char     *ReadSubjectToken (char *dest, char **ptr);
  213. BOOL    isnumber (char *str);
  214. BOOL    SearchThreadNames (char *name);
  215. int    ParseMimeHeaderLine (TypCoded *thisDecode, char *line);
  216. int    ParseMimeContentType (TypCoded *thisDecode, char *line);
  217.  
  218. void CreateCodingStatusWnd();
  219. int    DecodeDataLine (TypCoded *decode, char *line);
  220. void     CreateUUTable();
  221. BOOL    TestIgnoreLine (char *line);
  222. int    IsDataLine (char *line);
  223. BOOL     TestDataLine (char *line);
  224. int     ThreadTable (char *dest, char *name);
  225. void    UpdateThreadStatus (int num, char *str);
  226.  
  227. void    ExecuteDecodedFile (int num, char *fileName);
  228.  
  229. #if defined(DEBUG_DECODE) || defined(DEBUG_MEM)
  230. #define DEBUG_FILE "coding.log"
  231. void     DebugLog();
  232. void     InitDebugLog();
  233. char     debug[MAXCOMMLINE];
  234. OFSTRUCT debugFileStruct;
  235. #endif
  236.  
  237. #if defined(DEBUG_DECODE) || defined(DEBUG_MEM)
  238. /* ------------------------------------------------------------------------
  239.  * Debug log handler
  240.  * Open/close the file for every addition to log, so all info is safely
  241.  * captured in case of GPF
  242.  */
  243. void
  244. DebugLog ()
  245. {
  246.     HFILE hDebugFile;
  247.  
  248.         if ((hDebugFile = OpenFile ((char far *)NULL, &debugFileStruct, OF_REOPEN|OF_WRITE)) >= 0)
  249.     {       
  250.         _llseek(hDebugFile, 0L, 2);    /* go to end */
  251.             _lwrite(hDebugFile, debug, strlen(debug));
  252.             _lclose(hDebugFile);
  253.         }
  254. }
  255. void
  256. InitDebugLog ()
  257. {
  258.     HFILE hDebugFile;
  259.  
  260.         if ((hDebugFile = OpenFile ((char far *)DEBUG_FILE, &debugFileStruct, OF_CREATE)) >= 0)
  261.     {
  262.             sprintf(debug, "New log");
  263.             _lwrite(hDebugFile, debug, strlen(debug));
  264.             _lclose(hDebugFile);
  265.         }
  266. }
  267. #endif
  268. /* ------------------------------------------------------------------------
  269.  * Decode a file
  270.  * Uses a file instead of the comm article as a line-provider to the 
  271.  * decode routines
  272.  */
  273. void
  274. DecodeFile (HWND hParentWnd)
  275. {
  276.     FILE *DecodeFile;
  277.         char mybuf[MAXINTERNALLINE], fileName[MAXFILENAME], *ptr;
  278.         int result;
  279.  
  280.         if (AskForExistingFileName (hParentWnd, fileName, "Open encoded file") == FAIL)
  281.             return;
  282.  
  283.     DecodeInit();
  284.     if ((DecodeFile = fopen (fileName, "r")) == NULL)
  285.     {
  286.         MessageBox (hParentWnd, "Failure to read file", "File error", MB_OK);
  287.         return;
  288.     } 
  289.     if ((currentCoded = InitCoded(hParentWnd)) == NULL)
  290.     {
  291.         MessageBox (hParentWnd, "Unable to continue due to memory constraints.  Aborted", "Init Coded Object Error", MB_OK);
  292.         return;
  293.     }
  294.            while (1)
  295.            {
  296.                if ((ptr = fgets(mybuf, MAXINTERNALLINE, DecodeFile)) == NULL)
  297.                    strcpy (mybuf, "EOF");    // make sure wrap up occurs
  298.  
  299.         result = DecodeLine (currentCoded, mybuf);
  300.         if (result == FAIL)
  301.         {
  302.                  MessageBox (hParentWnd, "Aborted decode", "Problems during decode", MB_OK | MB_ICONEXCLAMATION);
  303.             goto abortDecodeFile;
  304.         }           
  305.         if (result == END_BLOCK)
  306.         {
  307.             if (CompleteThisDecode () == FAIL)
  308.             {
  309.                      MessageBox (hParentWnd, "Aborted decode", "Problems during decode", MB_OK | MB_ICONEXCLAMATION);
  310.                 goto abortDecodeFile;
  311.             }           
  312.                if ((currentCoded = InitCoded(hParentWnd)) == NULL)
  313.             {
  314.                 MessageBox (hParentWnd, "Unable to continue due to memory constraints.  Aborted", "Init Coded Object Error", MB_OK);
  315.                 goto abortDecodeFile;
  316.             }
  317.         }
  318.         if (ptr == NULL)    // EOF
  319.             break;
  320.     }
  321.  
  322.     if (currentCoded != NULL)    // finish final block
  323.         CompleteThisDecode ();
  324.    
  325.    abortDecodeFile:;
  326.           fclose(DecodeFile);
  327.     DecodeDone ();
  328. }
  329. /* ------------------------------------------------------------------------
  330.  * Decode a doc
  331.  * Uses a doc instead of the comm article as a line-provider to the 
  332.  * decode routines
  333.  */
  334. void
  335. DecodeDoc (HWND hParentWnd, TypDoc *Document)
  336. {
  337.         int result;
  338.     TypBlock far *BlockPtr;
  339.     TypLine far *LinePtr;
  340.             
  341.     DecodeInit();
  342.     if ((currentCoded = InitCoded(hParentWnd)) == NULL)
  343.     {
  344.         MessageBox (hParentWnd, "Unable to continue due to memory constraints.  Aborted", "Init Coded Object Error", MB_OK);
  345.         return;
  346.     }
  347.     
  348.     LockLine (Document->hFirstBlock, sizeof (TypBlock), (TypLineID) 0L, &BlockPtr, &LinePtr);
  349.     while (LinePtr->length != END_OF_BLOCK)
  350.     {
  351.         result = DecodeLine (currentCoded, 
  352.                 ((char far *) LinePtr) + sizeof (TypText) + sizeof (TypLine));
  353.  
  354.         if (result == FAIL)
  355.         {
  356.                  MessageBox (hParentWnd, "Aborted decode", "Problems during decode", MB_OK | MB_ICONEXCLAMATION);
  357.             goto abortDecodeDoc;
  358.         }           
  359.  
  360.         if (result == END_BLOCK)
  361.         {
  362.             if (CompleteThisDecode () == FAIL)
  363.             {
  364.                      MessageBox (hParentWnd, "Aborted decode", "Problems during decode", MB_OK | MB_ICONEXCLAMATION);
  365.                 goto abortDecodeDoc;
  366.             }           
  367.                if ((currentCoded = InitCoded(hParentWnd)) == NULL)
  368.             {
  369.                 MessageBox (hParentWnd, "Unable to continue due to memory constraints.  Aborted", "Init Coded Object Error", MB_OK);
  370.                 return;
  371.             }
  372.         }
  373.         NextLine (&BlockPtr, &LinePtr);
  374.     }
  375.     if (currentCoded != NULL)    // finish final block
  376.         CompleteThisDecode ();
  377.    
  378.    abortDecodeDoc:;
  379.     GlobalUnlock (BlockPtr->hCurBlock);
  380.     DecodeDone ();
  381. }
  382. /* ------------------------------------------------------------------------
  383.  *    Encode a file and ask the user for a file to name to store it in
  384.  */
  385. void
  386. EncodeToFile (HWND hParentWnd, char *inFile)
  387. {
  388.    register unsigned long i;
  389.    char fileName[MAXFILENAME];
  390.    OFSTRUCT outFileStruct;
  391.    HFILE hAttachFile;
  392.    TypTextBlock *encodeData;
  393.  
  394.    if ((encodeData = InitTextBlock (hParentWnd)) != NULL)
  395.    {
  396.       CreateStatusArea(hParentWnd);
  397.       strcpy (currentCoded->ident, inFile);    // status window info
  398.  
  399.       if (Encode (encodeData, inFile, ADD_TO_FILE) != FAIL)
  400.       {
  401.     fileName[0]='\0';        
  402.     if (AskForNewFileName (hParentWnd, fileName, "", FALSE) != FAIL)
  403.     {
  404.        if ((hAttachFile = OpenFile ((char far *) fileName, &outFileStruct, OF_CREATE)) < 0)
  405.         MessageBox(hParentWnd, "Unable to open output file", "File Error", MB_OK|MB_ICONSTOP);
  406.        else
  407.        {
  408.           for (i = 0; i < encodeData->numLines; i++)
  409.           _lwrite (hAttachFile, TextBlockLine (encodeData, i), lstrlen(TextBlockLine (encodeData, i)));
  410.           _lclose (hAttachFile);
  411.        }
  412.     }    
  413.       }     
  414.       FreeTextBlock (encodeData);
  415.       DestroyStatusArea ();
  416.    }   
  417. }
  418.  
  419. /* ------------------------------------------------------------------------
  420.  *    Create a status window a coding block used for status info
  421.  *    the currentCoded block is purely for status in this case
  422.  *    This is used by attach and EncodeFile and ReadFileToTextBlock
  423.  *    to show status in progress
  424.  *    Use UpdateBlockStatus to update/display status
  425.  *    Use DestroyStatusArea to clean up when done
  426.  */
  427. void
  428. CreateStatusArea (HWND hParentWnd)
  429. {
  430.     if ((currentCoded = InitCoded(hParentWnd)) == NULL)
  431.         return;
  432.     CreateCodingStatusWnd();
  433.     currentCoded->sequence = 1;        // status window info
  434.  
  435. }
  436.  
  437. void
  438. DestroyStatusArea ()
  439. {
  440.     DestroyCodedBlock (¤tCoded);
  441.     DestroyWindow (hCodedBlockWnd);
  442.     hCodedBlockWnd = (HWND)NULL;
  443. }
  444.  
  445. void
  446. CreateCodingStatusWnd()
  447. {
  448.     /* Create coding status window, top center */
  449.     hCodedBlockWnd = CreateWindowEx (WS_EX_DLGMODALFRAME, "WinVnBlockCoding", "Block Encoding Status",
  450.             WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_THICKFRAME,
  451.             (xScreen-STATUSWIDTH)>>1, 1, STATUSWIDTH, STATUSHEIGHT,
  452.             (HWND)NULL, (HMENU)NULL, hInst, (void far *)NULL);
  453.     
  454.     SetHandleBkBrush( hCodedBlockWnd, hStatusBackgroundBrush);
  455.     ShowWindow (hCodedBlockWnd, SW_SHOWNORMAL);
  456. }
  457.  
  458.  
  459. /* ------------------------------------------------------------------------
  460.  *    Adds text to a thread coding status block, and refreshes
  461.  *    the thread status window
  462.  */    
  463. void
  464. UpdateThreadStatus (int num, char *str)
  465. {
  466.     AddLineToTextBlock (threadList[num]->statusText, str);
  467.     InvalidateRect (threadList[num]->statusText->hTextWnd, NULL, FALSE);
  468.     UpdateWindow (threadList[num]->statusText->hTextWnd);
  469. }
  470.  
  471. /* ------------------------------------------------------------------------
  472.  *    Refreshes the block status window
  473.  */    
  474. void
  475. UpdateBlockStatus ()
  476. {
  477.     InvalidateRect (hCodedBlockWnd, NULL, FALSE);
  478.     UpdateWindow (hCodedBlockWnd);
  479. }
  480.  
  481. /* ------------------------------------------------------------------------
  482.  *    Encode a file 
  483.  *    Called _after_ the attach dialog, so all globals for this encode
  484.  *    are set  (sorry about the globals...)
  485.  *    Result is encoded file in TextBlock 
  486.  *    Assumes currentCoded is initialized
  487.  */
  488. int 
  489. Encode (TypTextBlock *textBlock, char *fileName, int mode)
  490. {
  491.     HFILE hFile;
  492.         int numRead, lineLen, start;
  493.     register int i;
  494.     unsigned char inBuf[CODE_LINE_LEN];
  495.     unsigned char outLine[MAXINTERNALLINE];
  496.     extern char *NameWithoutPath ();
  497.  
  498.     CodingState = ATTACH_PROCESSING;
  499.  
  500.     // Set up encoding map
  501.     switch (EncodingTypeNum)
  502.     {
  503.     case CODE_BASE64:    
  504.         codingTable = base64Table;
  505.         break;
  506.     case CODE_UU:
  507.         codingTable = uuTable;
  508.         break;
  509.     case CODE_XX:
  510. //    Note, XX table is hard coded in declarations for simplicity
  511.         codingTable = xxTable;
  512.         break;
  513.     case CODE_CUSTOM:
  514.         codingTable = UserCodingTable;
  515.         // add 2 table lines
  516.         if (AddEndedLineToTextBlock (textBlock, "table", mode))
  517.             return (FAIL);
  518.         memmove (str, UserCodingTable, 32);
  519.         str[32] = '\0';
  520.         if (AddEndedLineToTextBlock (textBlock, str, mode))
  521.             return (FAIL);
  522.         memmove (str, &UserCodingTable[32], 32);
  523.         if (AddEndedLineToTextBlock (textBlock, str, mode))
  524.             return (FAIL);
  525.         break;
  526.     }
  527.  
  528.     // Prepare for encoding
  529.     switch (EncodingTypeNum)
  530.     {
  531.     case CODE_UU:
  532.     case CODE_XX:
  533.     case CODE_CUSTOM:
  534.         // these are 3-to-4 encodings with 1st char indicating line len
  535.         // and block starts with 'begin' line and ends with 'end' line
  536.         // add 'begin' line
  537.         NameWithoutPath (str, fileName);
  538.         sprintf (outLine, "begin 755 %s", str);
  539.         if (AddEndedLineToTextBlock (textBlock, outLine, mode))
  540.             return (FAIL);
  541.         currentCoded->numLines++;
  542.             // set 1st char to appropriate line length value
  543.             outLine[0] = codingTable[CODE_LINE_LEN];
  544.             start = 1;    // count includes the count char itself
  545.         break;
  546.     case CODE_BASE64:
  547.         // base64 is a 3-to-4 encoding, with no line len indicator and 
  548.         // no 'begin' or 'end' lines
  549.         start = 0;
  550.     }
  551.     lineLen = CODE_LINE_LEN;
  552.  
  553.     // open the file and have at it    
  554.         hFile = _lopen (fileName, OF_READ);
  555.         while (1)
  556.         {
  557.             if ((numRead = _lread(hFile, inBuf, lineLen)) == 0)
  558.                 break;
  559.         if (numRead < lineLen)    // last line length value
  560.         {
  561.             if (EncodingTypeNum != CODE_BASE64)
  562.                 outLine[0] = codingTable[numRead];
  563.             
  564.             for (i = numRead; i < lineLen; i++)
  565.                 inBuf[i] = 0;
  566.         }
  567.             EncodeLine (outLine, inBuf, start, numRead);
  568.         if (AddEndedLineToTextBlock (textBlock, outLine, mode))
  569.             return (FAIL);
  570.         currentCoded->numLines++;
  571.         currentCoded->numBytes += numRead;
  572.             if (currentCoded->numLines % STATUS_UPDATE_FREQ == 0)
  573.                 UpdateBlockStatus ();
  574.     }        
  575.     _lclose(hFile);
  576.     switch (EncodingTypeNum)
  577.     {
  578.     case CODE_UU:
  579.     case CODE_XX:
  580.     case CODE_CUSTOM:
  581.             // add zero length line
  582.             outLine[0] = codingTable[0];
  583.             outLine[1] = '\0';
  584.         if (AddEndedLineToTextBlock (textBlock, outLine, mode))
  585.             return (FAIL);
  586.         // add 'end' line
  587.         strcpy (outLine, "end");
  588.         if (AddEndedLineToTextBlock (textBlock, outLine, mode))
  589.             return (FAIL);
  590.         currentCoded->numLines+=2;
  591.         }
  592.     UpdateBlockStatus ();
  593.     
  594.     CodingState = INACTIVE;
  595.     return (SUCCESS);
  596. }
  597.     
  598. /* ------------------------------------------------------------------------
  599.  *    Encode num chars from line
  600.  *    Put data in outLine starting at start
  601.  */
  602. int 
  603. EncodeLine (unsigned char *outLine, unsigned char *line, int start, int num)
  604. {
  605.     register int i, j;
  606.     
  607.     for (j = start, i = 0; i < num; j+=4, i+=3)
  608.         EncodeUnit (&outLine[j], &line[i], (i+3 > num) ? num - i : 3);
  609.  
  610.     outLine[j] = '\0';
  611.     return (j);
  612. }
  613.     
  614. void
  615. EncodeUnit (unsigned char *out, unsigned char *in, int num)
  616. {
  617.            out[0] = codingTable[((in[0]>>2) & 63)];
  618.     out[1] = codingTable[(((in[0]<<4)|(in[1]>>4)) & 63)];
  619.     if (num == 1)
  620.     {
  621.         if (EncodingTypeNum == CODE_BASE64)
  622.             strcpy (&out[2], "==");
  623.         return;
  624.     }
  625.  
  626.     out[2] = codingTable[(((in[1]<<2)|(in[2]>>6)) & 63)];
  627.     if (num == 2)
  628.     {
  629.         if (EncodingTypeNum == CODE_BASE64)
  630.             strcpy (&out[3], "=");
  631.         return;
  632.     }
  633.  
  634.     out[3] = codingTable[(in[2] & 63)];
  635. }
  636. /* ------------------------------------------------------------------------
  637.  *    Init for decoding
  638.  *     Initialize the coding tables
  639.  *    Init threadList:  list of pointers to Thread lists 
  640.  *    (one thread for each file being decoded)
  641.  *        
  642.  */
  643. void
  644. DecodeInit ()
  645. {
  646.     register int i;
  647.     
  648. #ifdef DEBUG_MEM
  649.     InitDebugLog();
  650. #endif
  651.     
  652.         for (i = 0; i < MAX_DECODE_THREADS; i++)
  653.             threadList[i] = NULL;
  654.  
  655.     currentCoded = (TypCoded *) NULL;
  656.     CodingState = DECODE_SKIPPING;
  657.     numDecodeThreads = 0;
  658.     numDumbDecoded = 0;
  659.     currentDecodeThread = -1;    
  660.     thisNumBlocks = -1;
  661.     prevBlockIdent[0] = '\0';
  662.     thisContentEncoding = CODE_UNKNOWN;
  663.     prevContentEncoding = CODE_UNKNOWN;
  664.         customTable[0] = '\0';
  665.  
  666. #ifdef DEBUG_MEM
  667.     sprintf(debug, "\nInitialized decoding, %d threads", MAX_DECODE_THREADS);
  668.     DebugLog();
  669. #endif
  670.     // Create coding status window (open for duration of coding only)
  671.     CreateCodingStatusWnd();
  672.     UpdateBlockStatus ();
  673. }
  674.  
  675. /* ------------------------------------------------------------------------
  676.  * At this point, all threads in sequence should have been written and freed,
  677.  * If any threads left, we either had an incomplete decode of some file,
  678.  * or the file was encoded w/out sequence info, and we were waiting to 
  679.  * hopefully receive it all.  If we had an endflag, then write it in order
  680.  * received
  681.  * Accepts handle of parent window so it can display any 'incomplete' messages
  682.  */
  683. void
  684. DecodeDone ()
  685. {
  686.     char mybuf[MAXINTERNALLINE], name[MAXINTERNALLINE];
  687.  
  688. #ifdef DEBUG_MEM
  689.     sprintf(debug, "\nDone coding,  Wrapping up stray threads");
  690.     DebugLog();
  691. #endif
  692.     name[0]='\0';            // only show name if not verbose mode
  693.     while (numDecodeThreads > 0)    // always work on top of list [0]
  694.     {
  695.         if (!CodingStatusVerbose)
  696.             if (threadList[0]->name[0] != '\0')
  697.                 sprintf (name, "%s   ", threadList[0]->name);
  698.             else
  699.                 sprintf (name, "%s   ", threadList[0]->ident);
  700.  
  701.         if (threadList[0]->numBlocks == 0)
  702.         {    // premature end of file
  703.                     WriteDecodeThread (0);
  704.             sprintf (mybuf, "%sDecode is missing parts, written total size %ld", name, threadList[0]->totalBytes);
  705.             UpdateThreadStatus (0, mybuf);
  706.         }
  707.         else if (threadList[0]->contentEncoding != CODE_BASE64 &&
  708.                 !threadList[0]->codedBlockList[threadList[0]->numBlocks-1]->endFlag)
  709.         {
  710.             sprintf (mybuf, "%sEnd never found.  Cancelling", name);
  711.             UpdateThreadStatus (0, mybuf);
  712.         }
  713.         else if (threadList[0]->expectedNumBlocks > 0)
  714.         {    // there IS sequencing info, so we should not be here
  715.                     WriteDecodeThread (0);
  716.             sprintf (mybuf, "%sDecode is missing parts, written total size %ld", name, threadList[0]->totalBytes);
  717.             UpdateThreadStatus (0, mybuf);
  718.         }
  719.         else
  720.                 {
  721.             sprintf (mybuf, "%sCompleteness confidence is medium, written total size %ld", name, threadList[0]->totalBytes);
  722.             UpdateThreadStatus (0, mybuf);
  723.                     WriteDecodeThread (0);
  724.         }            
  725.         DestroyThread (0);    // decrements numDecodeThreads
  726.     }
  727.     currentCoded = NULL;
  728.     CodingState = INACTIVE;
  729.         CommDecoding = FALSE;
  730.     DestroyWindow (hCodedBlockWnd);
  731.     hCodedBlockWnd = (HWND)NULL;
  732. }    
  733.  
  734. /* ------------------------------------------------------------------------
  735.  *     Initialize a coded object, and initial data space
  736.  *    Returns ptr to object or NULL if failed
  737.  */
  738. TypCoded *
  739. InitCoded (HWND hParentWnd)
  740. {      
  741.     TypCoded *thisCoded = NULL;
  742.     
  743. #ifdef DEBUG_MEM
  744.     sprintf(debug, "\nInitializing a coded object");
  745.     DebugLog();
  746. #endif
  747.     if ((thisCoded = (TypCoded *) GlobalAllocPtr ( GMEM_MOVEABLE, sizeof (TypCoded))) == NULL)
  748.         return ((TypCoded *) NULL);
  749.     
  750. #ifdef DEBUG_MEM
  751.     sprintf(debug, "\nAllocing data size %d", BASE_BLOCK_SIZE);
  752.     DebugLog();
  753. #endif
  754.     if ((thisCoded->data = (char huge *) GlobalAllocPtr (GMEM_MOVEABLE, BASE_BLOCK_SIZE * sizeof (char))) == NULL)
  755.         return ((TypCoded *) NULL);
  756.  
  757.     thisCoded->maxBytes = BASE_BLOCK_SIZE;
  758.     thisCoded->numBytes = 0;
  759.     thisCoded->numLines = 0;
  760.     thisCoded->sequence = -1;
  761.     thisCoded->seqConfidence = 0;
  762.     thisCoded->name[0] = '\0';
  763.     thisCoded->ident[0] = '\0';
  764.     thisCoded->endFlag = thisCoded->beginFlag = FALSE;
  765.     thisCoded->hParentWnd = hParentWnd;
  766.         bossanovaMIME = FALSE;
  767.     
  768.     return (thisCoded);
  769. }    
  770.  
  771. /* ------------------------------------------------------------------------
  772.  *     Destroy a thread
  773.  *    Destroy all blocks in the thread
  774.  *    Remove the thread from the threadList
  775.  */
  776. void
  777. DestroyThread (int num)
  778.     register int i;
  779.     
  780. #ifdef DEBUG_MEM
  781.     sprintf(debug, "\nDestroying thread %d", num);
  782.     DebugLog();
  783. #endif
  784.     if (CodingStatusVerbose)
  785.         threadList[num]->statusText->IsBusy = FALSE;
  786.     
  787.     for (i = 0; i < threadList[num]->numBlocks; i++)
  788.         DestroyCodedBlock (&(threadList[num]->codedBlockList[i]));
  789.         
  790.     GlobalFreePtr (threadList[num]);
  791.  
  792.     for (i = num; i < numDecodeThreads; i++)
  793.         threadList[i] = threadList[i + 1];
  794.     
  795.     numDecodeThreads--;
  796.     if (currentDecodeThread == num)
  797.         currentDecodeThread = max (0, currentDecodeThread - 1);
  798. }
  799. /* ------------------------------------------------------------------------
  800.  *     Destroy a coded block structure
  801.  *    Free the huge data.  Takes a ptr to a ptr so it can NULL it when done
  802.  */
  803. void
  804. DestroyCodedBlock (TypCoded **thisCoded)
  805. {        
  806. #ifdef DEBUG_MEM
  807.     sprintf(debug, "\nDestroying block sequence %d", (*thisCoded)->sequence);
  808.     DebugLog();
  809. #endif
  810.     GlobalFreePtr ((*thisCoded)->data);
  811.     GlobalFreePtr (*thisCoded);
  812.         *thisCoded = NULL;
  813. }
  814.  
  815. /* ------------------------------------------------------------------------
  816.  *     Given a file name, find the associated thread number  
  817.  *    Returns -1 if no thread by that name exists
  818.  */
  819. int
  820. GetThreadByName (char *name)
  821. {
  822.     int i, result;
  823.     
  824.     for (result = -1, i = 0; i < numDecodeThreads && result == -1; i++)
  825.         if (!_stricmp (name, threadList[i]->name))
  826.             result = i;
  827.  
  828.     return (result);
  829. }
  830. /* ------------------------------------------------------------------------
  831.  *     Determine if a thread has already been started for this ident
  832.  *    if yes, add decode object to that thread
  833.  *    otherwise, alloc a new thread list structure, add this block to it
  834.  *    At end, currentDecodeThread is set to handle of thread
  835.  */
  836. BOOL                                                           
  837. AddToThreadList ()
  838. {
  839.     register int i;
  840.     int num;
  841.     char mybuf[MAXINTERNALLINE];
  842.     int x, y, width, height, maxX, maxY;
  843.     
  844.      if (DumbDecode)
  845.      {    
  846.         if (numDecodeThreads == 0)
  847.              num = -1;
  848.         else 
  849.              num = 0;
  850.     } else
  851.      /* Search existing threads for an ident match.  If
  852.       * no match found, or no threads exist yet, add new thread.
  853.       */
  854.         for (num = -1, i = 0; i < numDecodeThreads; i++)
  855.             if (!_stricmp (currentCoded->ident, threadList[i]->ident))
  856.                 num = i;
  857.  
  858.     if (num == -1)        /* add a new thread */
  859.     {
  860.         if ((numDecodeThreads + 1) > MAX_DECODE_THREADS)    
  861.         {
  862.             return (FAIL);
  863. /*            GlobalUnlock(decodeObjectHandles);
  864.               decodeObjectHandles = GlobalRealloc (decodeFileHandles,
  865.                   (numDecodeThreads + LIST_SIZE_INC) * sizeof (HGLOBAL), 
  866.                   GMEM_MOVEABLE);
  867.             threadList = (HGLOBAL *) GlobalLock (decodeFileHandles);
  868. */
  869.         }
  870.  
  871. // create a new DecodeThreadStruct object, store its handle in threadList,
  872. #ifdef DEBUG_MEM
  873.         sprintf(debug, "\nCreating new thread ident %s", currentCoded->ident);
  874.         DebugLog();
  875. #endif
  876.          num = numDecodeThreads;
  877.         numDecodeThreads++;
  878.  
  879.         threadList[num] = (TypDecodeThread *) GlobalAllocPtr (GMEM_MOVEABLE, sizeof (TypDecodeThread));
  880.         threadList[num]->expectedNumBlocks = 0;
  881.         threadList[num]->numBlocksWritten = 0;
  882.         threadList[num]->numBlocks = 0;
  883.         threadList[num]->totalBytes = 0;
  884.         threadList[num]->dosFileName[0] = '\0';
  885.         if (thisContentEncoding == CODE_CUSTOM)
  886.             strncpy (threadList[num]->customTable, customTable, CODINGTABLESIZE);
  887.         threadList[num]->contentEncoding = thisContentEncoding;
  888.         strcpy (threadList[num]->ident, currentCoded->ident);
  889.                 if (currentCoded->name[0] != '\0')
  890.             strcpy (threadList[num]->name, currentCoded->name);
  891.         else
  892.             threadList[num]->name[0] = '\0';
  893.  
  894.             if (CodingStatusVerbose || NumStatusTexts == 0)
  895.         {
  896.            if ((threadList[num]->statusText = InitTextBlock(hCodedBlockWnd)) == NULL)
  897.             MessageBox (hCodedBlockWnd, "Memory allocation error in text block", "Memory Error", MB_OK);
  898.                 
  899.                    if (NumStatusTexts + 1 > MAX_DECODE_THREADS);
  900.                        // ?????
  901.                 
  902.                    CodingStatusText[NumStatusTexts++] = threadList[num]->statusText;
  903.  
  904.            if (CodingStatusVerbose)
  905.                sprintf(mybuf, "Decoding Status for file %s", (threadList[num]->name[0]!='\0')?threadList[num]->name:threadList[num]->ident);
  906.            else
  907.                strcpy(mybuf, "Decoding Status");
  908.            
  909.            width = xScreen>>1;
  910.            height = (yScreen>>1) - CaptionHeight;
  911.            maxX = 3 * (width>>1);    /* 3/4 screen width  */
  912.            maxY = 3 * (height>>1);    /* 3/4 screen height */
  913.  
  914.            x = (NumStatusTexts * 10) % maxX;
  915.            y = (yScreen>>2) + (NumStatusTexts * CaptionHeight) % maxY;
  916.  
  917.            threadList[num]->statusText->hTextWnd =
  918.             CreateWindow ("WinVnCoding", mybuf,
  919.                 WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
  920.                 x, y, width, height,
  921.                 (HWND)NULL, (HMENU)NULL, hInst, (void far *)NULL);
  922.  
  923.            if (threadList[num]->statusText->hTextWnd == (HWND)NULL)
  924.            {
  925.             FreeTextBlock(threadList[num]->statusText);    
  926.             MessageBox (hCodedBlockWnd, "Couldn't create status text window","Window Creation Error", MB_OK);
  927.             return (FAIL);            
  928.            }
  929.            SetHandleBkBrush (threadList[num]->statusText->hTextWnd,
  930.                       hStatusBackgroundBrush);
  931.            ShowWindow (threadList[num]->statusText->hTextWnd, SW_SHOWNORMAL);
  932.                UpdateWindow (threadList[num]->statusText->hTextWnd);
  933.         }
  934.         else
  935.            threadList[num]->statusText = CodingStatusText[0];
  936.  
  937.     }
  938.     
  939. /* If this new block enlightens us with any useful thread info, update
  940.  * the thread
  941.  */
  942.     if (currentCoded->name[0] != '\0')
  943.         strcpy (threadList[num]->name, currentCoded->name);
  944. //    if (threadList[num]->contentType[0] == '\0')
  945. //        strcpy (threadList[num]->contentType, thisContentType);
  946.     if (threadList[num]->expectedNumBlocks == 0 && thisNumBlocks > 0)
  947.         threadList[num]->expectedNumBlocks = thisNumBlocks;
  948.     
  949.     threadList[num]->totalBytes += currentCoded->numBytes;
  950. /*
  951.  * Now, add this decode object to the thread codedBlockList
  952.  * Insert in correct sequence. 
  953.  * If no sequence info available, add to end of list, but before any end block
  954.  */
  955.     if (DumbDecode)
  956.         InsertBlockInThread(num, currentCoded, threadList[num]->numBlocks);
  957.     else
  958.     {    
  959.       if (threadList[num]->numBlocks != 0 && currentCoded->sequence == -1)
  960.       {    /* sequence unknown, add at end or before end block */
  961.         if (currentCoded->beginFlag)
  962.             InsertBlockInThread(num, currentCoded, 0);
  963.         else 
  964.         {
  965.             if (threadList[num]->codedBlockList[threadList[num]->numBlocks - 1]->endFlag)
  966.                 InsertBlockInThread(num, currentCoded, threadList[num]->numBlocks - 1);
  967.             else            
  968.                 InsertBlockInThread(num, currentCoded, threadList[num]->numBlocks);
  969.         }
  970.       }
  971.       else
  972.       {
  973.         for (i = 0; i < threadList[num]->numBlocks; i++)
  974.         {
  975.             if (threadList[num]->codedBlockList[i]->sequence == -1 || 
  976.                 threadList[num]->codedBlockList[i]->sequence >= currentCoded->sequence)
  977.                 break;
  978.         }
  979.         InsertBlockInThread (num, currentCoded, i);
  980.       }                                                  
  981.     }
  982.     currentDecodeThread = num;         
  983.     if (!CodingStatusVerbose)
  984.         return (SUCCESS);
  985.     
  986.     sprintf (mybuf, "Decoded block");
  987.     if (currentCoded->sequence == -1)
  988.     {
  989.         if (currentCoded->beginFlag || currentCoded->endFlag)
  990.         {
  991.             if (currentCoded->beginFlag)
  992.                 strcat (mybuf, ", begin block");
  993.             if (currentCoded->endFlag)
  994.                 strcat (mybuf, ", end block");
  995.         } else
  996.             strcat (mybuf, " sequence unknown");
  997.     }        
  998.     else
  999.     {
  1000.         sprintf (str, " %d", currentCoded->sequence);
  1001.         strcat (mybuf, str);
  1002.         if (threadList[num]->expectedNumBlocks > 0)
  1003.         {
  1004.             sprintf (str, " of %d.", threadList[num]->expectedNumBlocks);
  1005.             strcat (mybuf, str);
  1006.         }
  1007.         if (currentCoded->sequence == threadList[num]->numBlocksWritten + 1)
  1008.             strcat (mybuf, " In sequence");
  1009.         else
  1010.             strcat (mybuf, " Out of sequence");
  1011.     }
  1012.     UpdateThreadStatus (num, mybuf);
  1013.     thisNumBlocks = -1;
  1014.  
  1015.     return (SUCCESS);
  1016. }
  1017.  
  1018. /* ------------------------------------------------------------------------
  1019.  *     Insert/delete a block in a thread list
  1020.  *    Inserts and deletes will be O(n).  Since n will never be big,
  1021.  *    it's not worth the trouble (and space usage) of using a linked list
  1022.  *
  1023.  *    index should never be -1 (case of unkown sequence handled by caller)
  1024.  *    to insert at front of list, index = 0
  1025.  *    to insert at end of list, index = threadList[num]->numBlocks
  1026.  */
  1027. void
  1028. InsertBlockInThread (int num, TypCoded *block, int index)
  1029. {
  1030.     register int i;
  1031.     
  1032.     for (i = threadList[num]->numBlocks; i > index && i > 0 ; i--)
  1033.         threadList[num]->codedBlockList[i] = threadList[num]->codedBlockList[i-1];
  1034.      
  1035. #ifdef DEBUG_DECODE
  1036.     sprintf(debug, "\nInserting into thread %s at posn %d", threadList[num]->ident, i);
  1037.     DebugLog(); 
  1038. #endif
  1039.      threadList[num]->codedBlockList[i] = block;
  1040.             
  1041.     threadList[num]->numBlocks++;        
  1042.  
  1043.     return;
  1044. }
  1045.  
  1046. void
  1047. DeleteBlockFromThread (int num, int index)
  1048. {
  1049.     register int i;
  1050.     
  1051.     for (i = index; i < threadList[num]->numBlocks; i++)
  1052.         threadList[num]->codedBlockList[i] = threadList[num]->codedBlockList[i+1];
  1053.      
  1054. #ifdef DEBUG_DECODE
  1055.     sprintf(debug, "\nRemoved from thread %s at posn %d", threadList[num]->name, index);
  1056.     DebugLog();
  1057. #endif
  1058.     threadList[num]->numBlocks--;        
  1059.  
  1060.     return;
  1061. }
  1062.  
  1063. /* ------------------------------------------------------------------------
  1064.  *     Complete a decode block
  1065.  *    Adds to thread list
  1066.  *    Writes block to disk if possible (and any others now in sequence)
  1067.  *    If it ends a thread, make sure everything is written, and
  1068.  *    free up the thread
  1069.  */
  1070. BOOL
  1071. CompleteThisDecode ()
  1072. {
  1073.     char mybuf[MAXINTERNALLINE];
  1074.     int num, singleBlockDone, foundEnd;
  1075.  
  1076.     UpdateBlockStatus ();    // final size displayed
  1077. #ifdef DEBUG_DECODE
  1078.     sprintf(debug, "\nCompleteThisDecode for file %s, block %d",
  1079.             currentCoded->ident, currentCoded->sequence);
  1080.     DebugLog();
  1081. #endif
  1082.     if (currentCoded->numBytes == 0)
  1083.     {
  1084. #ifdef DEBUG_DECODE
  1085.         sprintf(debug, "\nNon-data block.  Discarding it.");
  1086.         DebugLog();
  1087. #endif
  1088.         DestroyCodedBlock (¤tCoded);
  1089.         return (SUCCESS);
  1090.     }
  1091.     
  1092.     if (DumbDecode)
  1093.     {        
  1094.         if (numDumbDecoded == 0 && !currentCoded->beginFlag)
  1095.             return (SUCCESS); // Dumb skipping a data block
  1096.         if (numDumbDecoded > 0 && currentCoded->beginFlag)
  1097.         {        // found next begin without an end
  1098.             if (CodingStatusVerbose)
  1099.                 sprintf (mybuf, "Decode missing end, total size %ld, wrote to file %s", threadList[num]->totalBytes, threadList[num]->dosFileName);
  1100.             else
  1101.                 sprintf (mybuf, "%s   Decode missing end, total size %ld, wrote to file %s", 
  1102.             threadList[num]->name, threadList[num]->totalBytes, threadList[num]->dosFileName);
  1103.             UpdateThreadStatus (num, mybuf);
  1104.             DestroyThread(num);
  1105.             numDumbDecoded = 0;
  1106.         }
  1107.     }                    
  1108.         else
  1109.     // if for some reason (?) we didn't get a begin, but this is block 1
  1110.     if (currentCoded->sequence == 1 && 
  1111.         currentCoded->seqConfidence == HIGH && 
  1112.         !currentCoded->beginFlag)
  1113.     {
  1114.         currentCoded->beginFlag;
  1115.         strcpy (currentCoded->name, currentCoded->ident);
  1116.     }    
  1117.     
  1118.     if (AddToThreadList () == FAIL)
  1119.         return (FAIL);
  1120.     
  1121.     prevContentEncoding = thisContentEncoding;
  1122.     thisContentEncoding = CODE_UNKNOWN;
  1123.     
  1124.     num = currentDecodeThread;    
  1125.     singleBlockDone = currentCoded->beginFlag && currentCoded->endFlag;
  1126.  
  1127.     if (!CodingStatusVerbose && 
  1128.        (threadList[num]->numBlocksWritten == 0 && threadList[num]->numBlocks == 1))
  1129.     {
  1130.         sprintf (mybuf, "%s   Decode in progress", (threadList[num]->name[0]!='\0')?threadList[num]->name:threadList[num]->ident);
  1131.         UpdateThreadStatus (num, mybuf);
  1132.     }
  1133.     
  1134.     if (DumbDecode)
  1135.     {
  1136.         if (WriteTopBlockToFile (num, &foundEnd) == FAIL)
  1137.             return (FAIL);
  1138.         numDumbDecoded++;
  1139.     }
  1140.         else
  1141.         {
  1142. /* If this block is both begin and end, then go straight to WriteDecodeThread
  1143.  * If currentCoded is in sequence, then it was added as block 0 in the 
  1144.  * thread's block list, and may have caused other blocks to now be in 
  1145.  * sequence as well.  Write all blocks which are in sequence now.
  1146.  */
  1147.       if (!singleBlockDone && currentCoded->sequence != -1 && 
  1148.           currentCoded->seqConfidence != 0)
  1149.         while (threadList[num]->numBlocks != 0)
  1150.         {
  1151.             if (threadList[num]->codedBlockList[0]->sequence == threadList[num]->numBlocksWritten)
  1152.             {    // skip duplicate block sequence
  1153.                 DestroyCodedBlock (¤tCoded);    // threadList[num]->codedBlockList[0]
  1154.                             DeleteBlockFromThread (num, 0);
  1155.                             break;
  1156.                     }
  1157.             if (threadList[num]->codedBlockList[0]->sequence != threadList[num]->numBlocksWritten + 1)
  1158.                 break;
  1159. #ifdef DEBUG_DECODE
  1160.             sprintf(debug, "\nBlock in sequence, writing it, file %s, block %d",
  1161.                 threadList[num]->name, threadList[num]->codedBlockList[0]->sequence);
  1162.             DebugLog();
  1163. #endif
  1164.             if (WriteTopBlockToFile (num, &foundEnd) == FAIL)
  1165.                 return (FAIL);
  1166.          }
  1167.      }    
  1168.     if (singleBlockDone || (foundEnd && DumbDecode) ||
  1169.         (foundEnd && threadList[num]->expectedNumBlocks > 0 && 
  1170.         threadList[num]->numBlocksWritten >= threadList[num]->expectedNumBlocks))
  1171.     {
  1172. #ifdef DEBUG_DECODE
  1173.         sprintf(debug, "\nThread complete: file %s", threadList[num]->name);
  1174.         DebugLog();
  1175. #endif
  1176.            if (WriteDecodeThread(num) == FAIL)
  1177.         {
  1178.             DestroyThread(num);
  1179.             currentCoded = NULL;
  1180.                return (FAIL);
  1181.            }
  1182.  
  1183.         if (CodingStatusVerbose)
  1184.             sprintf (mybuf, "Decode complete, total size %ld, wrote to file %s", threadList[num]->totalBytes, threadList[num]->dosFileName);
  1185.         else
  1186.             sprintf (mybuf, "%s   Decode complete, total size %ld, wrote to file %s", 
  1187.         threadList[num]->name, threadList[num]->totalBytes, threadList[num]->dosFileName);
  1188.         UpdateThreadStatus (num, mybuf);
  1189.  
  1190.         DestroyThread(num);
  1191.         numDumbDecoded = 0;
  1192.     }
  1193.     currentCoded = NULL;
  1194.     return (SUCCESS);
  1195. }            
  1196.             
  1197. /* ------------------------------------------------------------------------
  1198.  *     Write data for the top block of a thread to a file, and remove
  1199.  *    the top block from the thread
  1200.  */
  1201. BOOL
  1202. WriteTopBlockToFile (int num, int *endFlag)
  1203. {
  1204.     char mybuf[MAXINTERNALLINE];
  1205.  
  1206.     if (WriteBlockToFile (num, threadList[num]->codedBlockList[0]) == FAIL)
  1207.     {
  1208.         sprintf (mybuf, "Could not write to file %s", threadList[num]->dosFileName);
  1209.         UpdateThreadStatus (num, mybuf);
  1210.         DestroyThread(num);
  1211.         return (FAIL);
  1212.     }
  1213.     
  1214.     *endFlag = threadList[num]->codedBlockList[0]->endFlag;
  1215.     DestroyCodedBlock (&(threadList[num]->codedBlockList[0]));
  1216.     DeleteBlockFromThread (num, 0);
  1217.     threadList[num]->numBlocksWritten++; 
  1218.     return (SUCCESS);
  1219. }
  1220.     
  1221. /* ------------------------------------------------------------------------
  1222.  *     Write data for a thread to a file
  1223.  */
  1224. BOOL
  1225. WriteDecodeThread (int num)
  1226. {
  1227.     register int i;
  1228.     char mybuf[MAXINTERNALLINE];
  1229.         
  1230.     for (i = 0; i < threadList[num]->numBlocks; i++)
  1231.     {
  1232. #ifdef DEBUG_DECODE
  1233.         sprintf(debug, "\nSaving sequence %d", threadList[num]->codedBlockList[i]->sequence);
  1234.         DebugLog();
  1235. #endif
  1236.         if (WriteBlockToFile (num, threadList[num]->codedBlockList[i]) == FAIL)
  1237.         {
  1238.             sprintf (mybuf, "Could not write to file %s", threadList[num]->dosFileName);
  1239.             UpdateThreadStatus (num, mybuf);
  1240.             return (FAIL);
  1241.         }
  1242.     }
  1243.     if (ExecuteDecodedFiles)
  1244.         ExecuteDecodedFile(num, threadList[num]->dosFileName);
  1245.  
  1246.     return (SUCCESS);
  1247. }
  1248.  
  1249. /* ------------------------------------------------------------------------
  1250.  *     Write block data to a file
  1251.  *    Verify thread file name will work in DOS, and request a new file
  1252.  *    name if necessary
  1253.  *     Accepts handle of parent window to allow any necessary dialogs
  1254.  */
  1255. BOOL
  1256. WriteBlockToFile(int num, TypCoded *thisDecode)
  1257.     register unsigned long i;
  1258.     unsigned int chunkSize;
  1259.     char    actualFileName[MAXFILENAME], mybuf[MAXINTERNALLINE];
  1260.         OFSTRUCT outFileStruct;
  1261.     HFILE     hWriteFile;
  1262.     UINT    fileMode;
  1263.  
  1264. #define    CHUNK_SIZE 65500    /* must not exceed UINT (65534) */        
  1265.     
  1266.     if (threadList[num]->dosFileName[0] != '\0') {
  1267.         fileMode = OF_WRITE;
  1268.         if (strchr (threadList[num]->dosFileName, '\\') == NULL)
  1269.         {
  1270.             strcpy (actualFileName, DecodePathName);
  1271.             if (actualFileName[strlen(actualFileName)-1] != '\\')
  1272.                 strcat(actualFileName, "\\");
  1273.             strcat(actualFileName, threadList[num]->dosFileName);
  1274.             }
  1275.         else
  1276.            strcpy (actualFileName, threadList[num]->dosFileName);
  1277.     }
  1278.     else 
  1279.     {
  1280.     /* First time write to file
  1281.      */
  1282.         fileMode = OF_CREATE;
  1283.                 
  1284.                 actualFileName[0] = '\0';
  1285.         if (threadList[num]->name[0] != '\0')
  1286.             strcpy (threadList[num]->dosFileName, threadList[num]->name);
  1287.         else if (threadList[num]->ident[0] != '\0')
  1288.             strcpy (threadList[num]->dosFileName, threadList[num]->ident);
  1289.         if (threadList[num]->dosFileName[0] != '\0')
  1290.         {
  1291.             strcpy (actualFileName, DecodePathName);
  1292.             if (actualFileName[strlen(actualFileName-1)] != '\\')
  1293.                 strcat(actualFileName, "\\");
  1294.             strcat(actualFileName, threadList[num]->dosFileName);
  1295.         }
  1296.  
  1297.         /* smart filer work */
  1298.         if (SmartFile(hCodedBlockWnd, actualFileName) == FAIL)
  1299.             return (FAIL);
  1300.  
  1301.         strcpy (threadList[num]->dosFileName, actualFileName);
  1302.     }
  1303.         
  1304.         if ((hWriteFile = OpenFile ((char far *) actualFileName, &outFileStruct, fileMode)) < 0)
  1305.     {
  1306.         MessageBox(hCodedBlockWnd, "Unable to open output file", "File Error", MB_OK|MB_ICONSTOP);
  1307.         return (FAIL);
  1308.         }
  1309.         if (fileMode == OF_WRITE)
  1310.             _llseek (hWriteFile, 0L, 2);    /* append */
  1311.             
  1312.     for (i = 0L; i < thisDecode->numBytes; i += chunkSize)
  1313.     {
  1314.                if (i + CHUNK_SIZE > thisDecode->numBytes)
  1315.                    chunkSize = (unsigned int) (thisDecode->numBytes - i);
  1316.                else
  1317.                    chunkSize = CHUNK_SIZE;
  1318.  
  1319.                if (_lwrite(hWriteFile, &(thisDecode->data[i]), chunkSize) != chunkSize)
  1320.         {
  1321.             MessageBox(hCodedBlockWnd, "Error writing to file", "File Error", MB_OK|MB_ICONSTOP);
  1322.                    _lclose(hWriteFile);
  1323.             return (FAIL);
  1324.             }
  1325.         }
  1326.  
  1327.     if (CodingStatusVerbose)
  1328.     {
  1329.         strcpy (mybuf, "     Wrote block ");
  1330.         if (thisDecode->sequence > 0)
  1331.         {
  1332.             sprintf (str, "%d ", thisDecode->sequence);
  1333.             strcat (mybuf, str);
  1334.         }
  1335. //        sprintf (str, "to file %s", threadList[num]->dosFileName);
  1336. //        strcat (mybuf, str);
  1337.         UpdateThreadStatus (num, mybuf);
  1338.     }
  1339.            _lclose(hWriteFile);
  1340.     return (SUCCESS);
  1341. }
  1342.  
  1343. /* ------------------------------------------------------------------------
  1344.  *     Decode a line in article.  Store in thisDecode
  1345.  */
  1346. int  
  1347. DecodeLine(TypCoded *thisDecode, char *line)
  1348. {
  1349.     register int i;
  1350.     static int table_count;
  1351.     char thisBlockName[MAXINTERNALLINE];
  1352.          int mode;
  1353.  
  1354.     if (strlen(line) == 0)    
  1355.         return (SUCCESS);
  1356.  
  1357.     thisDecode->numLines++;
  1358.     if (thisDecode->numLines % STATUS_UPDATE_FREQ == 0)
  1359.         UpdateBlockStatus ();
  1360.     
  1361.     switch (CodingState)
  1362.     {
  1363.     case DECODE_SKIPPING: 
  1364.         if (strlen(line) < 3)    // if we're skipping, ignore any really short line
  1365.             return (SUCCESS);
  1366.  
  1367.         // encoded UU/XX/Custom data always starts with line 
  1368.         // like 'begin <mode> <file-name>'
  1369.         if (!strncmp (line, "begin", 5) &&
  1370.             sscanf (line, "%*s %d %s", &mode, thisBlockName) == 2)
  1371.                 {
  1372. #ifdef DEBUG_DECODE
  1373.             sprintf(debug, "\nStart of new encoded file %s, mode %d", thisBlockName, mode);
  1374.             DebugLog();
  1375. #endif
  1376.             if (thisBlockName[0] != '\0')
  1377.                 strcpy (thisDecode->name, strlwr(thisBlockName));
  1378.                         else
  1379.                 strcpy (thisDecode->name, thisDecode->ident);
  1380.                                     
  1381.             thisDecode->sequence = 1;
  1382.             thisDecode->beginFlag = TRUE;
  1383. //            thisDecode->mode = mode;
  1384.  
  1385.             CodingState = DECODE_PROCESSING;
  1386.             return (SUCCESS);
  1387.         }     
  1388. /* Check for keywords in the non-data lines which may aid in describing
  1389.  * the name for this data, the sequence, a custom table, etc
  1390.  */
  1391.          else if (!DumbDecode && !_strnicmp(line, "subject:", 8))
  1392.              ParseInfoLine (thisDecode, &line[8], TRUE);
  1393.          else if (!DumbDecode && !_strnicmp(line, "summary:", 8))
  1394.             ParseInfoLine (thisDecode, &line[8], FALSE);
  1395.          else if (!DumbDecode && ParseAppSpecificLine (thisDecode, line))
  1396.             return (SUCCESS);
  1397.          else if (!strncmp(line, "table", 5))
  1398.          {    // next two lines are table
  1399.              CodingState=DECODE_GET_TABLE;
  1400.             table_count = 0;
  1401.              return (SUCCESS);
  1402.          }
  1403.                      
  1404. /*        else if (ParseMimeHeaderLine(thisDecode, line) == SUCCESS)
  1405.             return (SUCCESS);
  1406. */
  1407. /* Skipping to find new block of data.
  1408.  * Skip until a data line (a line with the correct length) is found
  1409.  */        
  1410.          else if (IsDataLine(line))
  1411.         {   
  1412. #ifdef DEBUG_DECODE
  1413.             sprintf(debug, "\nFound start of next data section", line);
  1414.             DebugLog();
  1415. #endif
  1416.                          CodingState = DECODE_PROCESSING;
  1417.                            // found good line, process it and continue processing
  1418.                            return (DecodeDataLine(thisDecode, line));
  1419.         }
  1420. #ifdef DEBUG_DECODE
  1421.         sprintf(debug, "\nskipped: %s", line);
  1422.         DebugLog();
  1423. #endif
  1424.         return (SUCCESS);        // continue skipping 
  1425.  
  1426.     case DECODE_GET_TABLE:
  1427.     // This is one of two lines containing table info
  1428.         memmove ((customTable + table_count * 32), line, 32);
  1429.  
  1430.         if (++table_count == 2)
  1431.         {
  1432. #ifdef DEBUG_MAP
  1433.             strncpy (str, customTable, 64);
  1434.             str[64]='\0';
  1435.             sprintf(debug, "\nfound table: %s", str);
  1436.             DebugLog();
  1437. #endif
  1438.             CodingState = DECODE_SKIPPING;
  1439.             if (i = CreateCodingMap (CodingMap[CODE_CUSTOM], customTable) != -1)
  1440.             {
  1441. #ifdef DEBUG_MAP
  1442.                 sprintf (debug, "Invalid decoding table in block.  Duplicate character %c.",  i);
  1443.                 DebugLog();
  1444. #endif
  1445.                 customTable[0]='\0';    // ditch the table
  1446.             } 
  1447.             else
  1448.                 thisContentEncoding = CODE_CUSTOM;
  1449.         }
  1450.         return (SUCCESS);
  1451.             
  1452.     case DECODE_PROCESSING:
  1453. /* Some encoders place an END line at end of a section, and length it like 
  1454.  * a proper encoded line
  1455.  * Make sure we catch it, don't decode it as data, and switch back to skipping
  1456.  * Note the only End statement which means End of entire file is lower case
  1457.  * "end".  The other tags are ignored, i.e. "END", "End_of_section", etc
  1458.  */
  1459.         if (!_strnicmp (line, "end", 3) || !IsDataLine(line) ||
  1460.            (bossanovaMIME && !strcmp (&line[2], thisBoundary))) // skip '--'
  1461.         {
  1462. #ifdef DEBUG_DECODE    
  1463.             sprintf(debug, "\nSwitching back to skipping\nskipped: %s", line);
  1464.             DebugLog();
  1465. #endif
  1466.             CodingState = DECODE_SKIPPING;
  1467.  
  1468. /* If we are switching back to skipping and haven't really received any
  1469.  * data yet (< about a line's worth), then the line which gave us the coding type
  1470.  * was bogus (regular text line where first char happened to = encoded line 
  1471.  * length, Here's one: 'From: marnold@@cwis.unomaha.edu (Matthew Eldon Arnold)'
  1472.  * Ditch all data so far and the current table  and reprocess
  1473.  * this line.  Note if we have a custom table, then we trust it.
  1474.  */
  1475.             if (thisContentEncoding != CODE_CUSTOM && thisDecode->numBytes < 80)
  1476.             {
  1477.                 thisDecode->numBytes = 0;
  1478.                 thisContentEncoding = CODE_UNKNOWN;
  1479. #ifdef DEBUG_DECODE    
  1480.                 sprintf(debug, "\nBogus table!  Scrapping so far, reprocessing line: %s", line);
  1481.                 DebugLog();
  1482. #endif
  1483.                 thisDecode->numLines--;
  1484.                 return (DecodeLine (thisDecode, line));
  1485.             }
  1486.             strcpy (prevBlockIdent, thisDecode->ident);
  1487.         
  1488.                    if (!strncmp (line, "end", 3))
  1489.             {
  1490.                 thisDecode->endFlag = TRUE;
  1491.                 if (thisNumBlocks == -1 && thisDecode->sequence != -1)
  1492.                     thisNumBlocks = thisDecode->sequence;
  1493. #ifdef DEBUG_DECODE
  1494.                 sprintf(debug, "\nFound end of file %s", thisDecode->ident);
  1495.                 DebugLog();
  1496. #endif
  1497.             }                    
  1498.                 return (END_BLOCK);
  1499.         }
  1500.                   return (DecodeDataLine(thisDecode, line));
  1501.     }
  1502. }
  1503.  
  1504. /* ------------------------------------------------------------------------
  1505.  *  4 to 3 line decoder
  1506.  */
  1507. BOOL    DecodeDataLine (TypCoded *thisDecode, char *line)
  1508. {
  1509.     register unsigned int i, j;
  1510.     unsigned int decodedCount, numEncoded, numDecoded, checkSum, startNum, stop;
  1511.     unsigned char buf[4], outLine[120];
  1512.     char *thisMap = CodingMap[thisContentEncoding];
  1513.     
  1514.     switch (thisContentEncoding)
  1515.     {
  1516.     case CODE_QP:
  1517.        // not implemented yet
  1518.     return (FAIL);
  1519.     
  1520.     case CODE_UU:
  1521.     case CODE_XX:
  1522.     case CODE_CUSTOM:
  1523.     // these are 4-to-3 decodings which have the line length encoded
  1524.     // as the first char (count is # of chars after decoding)
  1525.     checkSum = decodedCount = thisMap[line[0]];
  1526.     numEncoded = 4 * ((thisMap[line[0]] + 2) / 3);    // don't include count char
  1527.     startNum = 1;
  1528.     break;
  1529.     case CODE_BASE64:
  1530.     // base64 is 4-to-3 decoding with nonexplicit line lengths 
  1531.     numEncoded = strlen(line);
  1532.     decodedCount = 3 * (numEncoded / 4);
  1533.     startNum = 0;
  1534.     break;
  1535.     }    
  1536.     for (i = startNum, numDecoded=0; numDecoded < decodedCount;)
  1537.     {
  1538.     // Get the next group of four characters 
  1539.     // Handle last group of characters in a base64 encoding specially -
  1540.     // padding '=' at end means we have fewer than 24 bits after decoding
  1541.     // Base64 end scenarios:
  1542.     //    'xx==' decodes to 8 bits
  1543.     //    'xxx=' decodes to 16 bits
  1544.     //    'xxxx' decodes to 24 bits
  1545.     //    'x===' can't happen
  1546.     stop = min(4, numEncoded - i + 1);
  1547.     for (j = 0; j < stop; j++, i++)
  1548.     {       
  1549.         if (thisContentEncoding == CODE_BASE64 && line[i] == '=')
  1550.         {
  1551.             buf[j] = 0;
  1552.             j--;
  1553.             break;
  1554.         }
  1555.         else
  1556.             buf[j] = thisMap[line[i]];
  1557.         checkSum += buf[j]; 
  1558.     }
  1559.     outLine[numDecoded++] = buf[0]<<2|buf[1]>>4;
  1560.     if (j == 1) break;
  1561.     outLine[numDecoded++] = buf[1]<<4|buf[2]>>2;
  1562.     if (j == 2) break;
  1563.     outLine[numDecoded++] = buf[2]<<6|buf[3];
  1564.     }
  1565.     if (numDecoded && AddDataToBlock (currentCoded, outLine, numDecoded) == FAIL)
  1566.     return (FAIL);
  1567.  
  1568. /*    if (checkSum%64 != line[i])
  1569.     {
  1570.         printf("\nChecksum error: %d vs. %d", checkSum%64, line[i]);
  1571.         break;
  1572.     } else
  1573.         printf("\nChecksum ok: %c vs. %c", checkSum%64, line[i]);
  1574. */
  1575.     return (SUCCESS);
  1576. }
  1577.  
  1578. /* ------------------------------------------------------------------------
  1579.  * AddDataToBlock is called on a line-by-line basis.
  1580.  * dataLen should rarely be > 100 bytes
  1581.  * The data is type huge, but it's just pointing to a string of chars, so
  1582.  * the size does not have to be a power of 2
  1583.  */
  1584. BOOL
  1585. AddDataToBlock (TypCoded *thisDecode, char *newData, unsigned int dataLen)
  1586. {
  1587.     if (thisDecode->numBytes + (unsigned long) dataLen > thisDecode->maxBytes)
  1588.     { 
  1589.             thisDecode->maxBytes += BASE_BLOCK_SIZE;
  1590. #ifdef DEBUG_MEM
  1591.         sprintf(debug, "\nReallocing data to %ld", thisDecode->maxBytes);
  1592.         DebugLog();
  1593. #endif
  1594.         if ((thisDecode->data = (char huge *) GlobalReAllocPtr (thisDecode->data, thisDecode->maxBytes, GMEM_MOVEABLE)) == NULL)    
  1595.             return (FALSE);
  1596.     }
  1597.     memmove (thisDecode->data + thisDecode->numBytes, newData, dataLen);
  1598.     thisDecode->numBytes += dataLen;
  1599.         return (SUCCESS);
  1600. }     
  1601.         
  1602. /* ------------------------------------------------------------------------
  1603.  *     Determine if the line is a data line
  1604.  */
  1605. BOOL
  1606. IsDataLine (char *line)
  1607. {
  1608.     if (thisContentEncoding == CODE_UNKNOWN)
  1609.     {
  1610. /* If this block has same ident as prev block, use same decode table
  1611.  * If this block has same ident as any existing threads, use same decode table
  1612.  * as matching thread
  1613.  * Otherwise, test line for UU, XX, or Base64, returning if find a fit
  1614.  */            
  1615.         if (currentCoded->ident[0] != '\0' && 
  1616.             !strcmp (currentCoded->ident, prevBlockIdent))
  1617.         {
  1618.             thisContentEncoding = prevContentEncoding;
  1619. #ifdef DEBUG_MAP
  1620.             strcpy (debug, "\nUsing same table as prev decode block");
  1621.             DebugLog();
  1622. #endif
  1623.         }
  1624.         else
  1625.             if ((thisContentEncoding = ThreadTable (customTable, currentCoded->ident)) != CODE_UNKNOWN)
  1626.             {
  1627.                if (thisContentEncoding == CODE_CUSTOM)
  1628.                 CreateCodingMap (CodingMap[CODE_CUSTOM], customTable);
  1629. #ifdef DEBUG_MAP
  1630.                 strcpy (debug, "\nUsing stored thread table");
  1631.                 DebugLog();
  1632. #endif
  1633.             }
  1634.             else
  1635.             {                
  1636.                 thisContentEncoding = CODE_UU;
  1637.                 if (TestDataLine (line))
  1638.                 {
  1639. #ifdef DEBUG_MAP
  1640.                     sprintf (debug, "\nUsing UU table: %s", line);
  1641.                     DebugLog();
  1642. #endif
  1643.                     return (TRUE);
  1644.                 }
  1645.                 thisContentEncoding = CODE_XX;
  1646.                 if (TestDataLine (line))
  1647.                 {
  1648. #ifdef DEBUG_MAP
  1649.                     sprintf (debug, "\nUsing XX table: %s", line);
  1650.                     DebugLog();
  1651. #endif
  1652.                     return (TRUE);
  1653.                 }
  1654.                 thisContentEncoding = CODE_BASE64;
  1655.                 if (TestDataLine (line))
  1656.                 {
  1657. #ifdef DEBUG_MAP
  1658.                     sprintf (debug, "\nUsing Base64 table: %s", line);
  1659.                     DebugLog();
  1660. #endif
  1661.                     return (TRUE);
  1662.                 }
  1663.                 thisContentEncoding = CODE_UNKNOWN;
  1664.                 return (FALSE);
  1665.             }
  1666.     }
  1667.     return (TestDataLine(line));
  1668. }
  1669.         
  1670. BOOL
  1671. TestDataLine (char *line)
  1672. {        
  1673.    unsigned int expectedLineLen, dataLen, lineLen;
  1674.    register unsigned int i;
  1675.    char *thisMap;
  1676.    
  1677.    thisMap = CodingMap[thisContentEncoding];
  1678.    lineLen = strlen(line);
  1679.    switch (thisContentEncoding)
  1680.    {
  1681.    case CODE_UU:
  1682.    case CODE_XX:
  1683.    case CODE_CUSTOM:
  1684. /*
  1685.  * The first char of a good data UU/XX/Custom line is the encoded character
  1686.  * count for the line.  
  1687.  * example M = ascii 77, decodes to 45.  This line will decode to 45 characters,
  1688.  * so the # encoded chars should be (int)(4 * ((n+2) / 3)) - (round up and re-encode)
  1689.  * So if line[0] is 'M', there should be 60 characters on the line
  1690.  * The count does not include the first count char, so the expected line 
  1691.  * length is count+1 (i.e. 61). 
  1692.  * If the line length is actually 2 + count, then we have a checksum (?)
  1693.  */ 
  1694.     expectedLineLen = 4 * ((thisMap[line[0]] + 2) / 3) + 1;
  1695.  
  1696.     if (lineLen < expectedLineLen)
  1697.          return (FALSE);
  1698. /*
  1699.  * Count the number of encoded data characters on the line (up to any whitespace)
  1700.  * (Some encoders pad with spaces at the end).  Don't forget, a space may be
  1701.  * a valid encoded char, so a proper line may very well end with a space.
  1702.  * Don't blindly remove all trailing white space!
  1703.  */        
  1704.      for (dataLen = lineLen; 
  1705.           isspace (line[dataLen-1]) && dataLen > 0 && dataLen != expectedLineLen; 
  1706.           --dataLen);
  1707.      
  1708.      // May have a checksum character, so allow for one extra char
  1709.      if (expectedLineLen != dataLen && expectedLineLen+1 != dataLen)
  1710.          return (FALSE);
  1711.      
  1712.      line[dataLen] = '\0';    // permanently chop off the white space
  1713.      // It's the right length, now check content for match w/ table
  1714.     for (i = 0; i < expectedLineLen; i++)
  1715.         if (thisMap[line[i]] == UNUSED)
  1716.             return (FALSE);
  1717.     return (TRUE);
  1718.  
  1719.     case CODE_BASE64:
  1720.     // permanently remove all trailing space
  1721.     while (lineLen > 0 && isspace (line[lineLen-1]))
  1722.         line[--lineLen] = '\0';
  1723.      
  1724.      // for base 64, just check if all chars in coding map (allow pad '=')
  1725.     for (i = 0; i < lineLen; i++)
  1726.         if (thisMap[line[i]] == UNUSED && line[i] != '=')
  1727.             return (FALSE);
  1728.     return (TRUE);
  1729.  
  1730.     case CODE_QP:
  1731.     // not implemented yet
  1732.     default:
  1733.         return (FALSE);
  1734.     }        
  1735. }                               
  1736.  
  1737. /* ------------------------------------------------------------------------
  1738.  *     Mappings for encoding/decoding
  1739.  */
  1740. int
  1741. CreateCodingMap(char *map, char *table)
  1742. {
  1743.     register unsigned int i;
  1744.     
  1745.     for (i=0; i < 128; i++)
  1746.         map[i] = UNUSED;
  1747.     
  1748.     // if you see a table[i] character, decode it to i
  1749.     // i.e. UU, table[1] is a '!'.  So a '!' should decode to 1
  1750.     
  1751.     for (i = 0; i < CODINGTABLESIZE; i++)
  1752.             if (map[table[i]] != UNUSED)
  1753.                 return (table[i]);    // table[i] is duplicate 
  1754.         else                
  1755.             map[table[i]]=i;
  1756.     
  1757. #ifdef DEBUG_MAP2
  1758.     sprintf(debug, "\nCoding Map:\n"); DebugLog();
  1759.     for (i=0; i < 128; i++)
  1760.     {
  1761.         sprintf(debug, "%d ",map[i]);
  1762.         DebugLog();
  1763.     } 
  1764. #endif
  1765.     return (-1);            
  1766. }
  1767.  
  1768. int   
  1769. ThreadTable (char *dest, char *ident)
  1770. {
  1771.     int num;
  1772.     register int i;
  1773.     
  1774.     for (num = -1, i = 0; i < numDecodeThreads; i++)
  1775.         if (!_stricmp (ident, threadList[i]->ident))
  1776.             num = i;
  1777.  
  1778.     if (num == -1)        // no thread by that name 
  1779.         return (CODE_UNKNOWN);
  1780.     else
  1781.     {
  1782.         if (threadList[num]->contentEncoding == CODE_CUSTOM)
  1783.             strncpy (dest, threadList[num]->customTable, CODINGTABLESIZE);
  1784.         return (threadList[num]->contentEncoding);
  1785.     }
  1786. }
  1787. #if 0
  1788. void
  1789. CreateUUTable()
  1790. {
  1791.     register unsigned int i;
  1792.  
  1793.     for (i=0; i < CODINGTABLESIZE; i++)
  1794.         uuTable[i] = i + 32;
  1795.     
  1796.     uuTable[0] = 96;        /* set space to map to back-quote */    
  1797. }
  1798. #endif
  1799.  
  1800. /* ------------------------------------------------------------------------
  1801.  *    Search through a subject: or BEGIN line 
  1802.  *    (for a Subject: line,  "Subject:" has already been removed).
  1803.  *
  1804.  *    Attempt to obtain a block number, and a total # of blocks
  1805.  *    Generate an identifier based on the subject, preferably based on the
  1806.  *    actual file name.  If guessIdent is TRUE, choose an ident even if
  1807.  *    it doesn't look like a fileName.  If guessIdent is FALSE, only fill
  1808.  *    ident if we see a fileName (word containing a dot).
  1809.  *
  1810.  *    Note: at this point, we haven't seen any MIME header, and we're not
  1811.  *    really expecting one.  So now is the time to get what we can
  1812.  *
  1813.  *    Common Subject styles which this function deals with:
  1814.  *    filename.ext 1/2 comment
  1815.  *    filename.ext(1/2)comment
  1816.  *    filename.ext (1/2) comment
  1817.  *    filename.ext [1/2] comment
  1818.  *    filename.ext 1 of 2 comment
  1819.  *    filename.ext part 1 of 2 comment
  1820.  *    filename.ext 1 of 2 comment
  1821.  *    This is part 1/2 of filename.ext
  1822.  *
  1823.  *    Also handles the following common BEGIN lines:
  1824.  *    BEGIN --- CUT HERE --- Cut Here --- cut here --- abcd.efg n/N
  1825.  *     BEGIN --- CUT HERE --- Cut Here --- cut here --- abcd.efg
  1826.  *    BEGIN-------cut here-------CUT HERE-------PART n               // This is TIN
  1827.  *    BEGIN -- CUT HERE -- cut here -- abcd.efg part n of N
  1828.  *    BEGIN---CUT HERE---BEGIN---CUT HERE---BEGIN PART n/N
  1829.  *
  1830.  *    For subject lines beginning with the comment, or free text, the
  1831.  *    name is harder to guess.  In these cases, prefer a word containing
  1832.  *    a dot (filename.ext), or if none, just take the first word.  Scan
  1833.  *    any existing threads to see if any of their identifiers matches.
  1834.  *    For example,
  1835.  *    another encoded file: filename.ext (1/2)
  1836.  *    testing encoded files (1/2)    i.e. ident would be testing
  1837.  *
  1838.  *     Known to be incorrectly handled by this function:
  1839.  *    filename.ext 3.4 (1/2)        i.e. name w/ version number
  1840.  *    filename.ext 001        i.e. sequence w/ no # parts
  1841.  *    filename.ext1            i.e. part number appended to file name
  1842.  */ 
  1843. #define SEEK_PARTNUM    1
  1844. #define SEEK_NUMPARTS    2
  1845. #define IGNORE_NUMBERS    3
  1846. void
  1847. ParseInfoLine (TypCoded *thisDecode, char *line, BOOL guessIdent)
  1848. {
  1849.     char tok[MAXINTERNALLINE], next[MAXINTERNALLINE];
  1850.     char guessName[MAXINTERNALLINE];
  1851.     char *ptr, *thisTok, *tmp;
  1852.     int  numberMode;
  1853.     
  1854.     numberMode = SEEK_PARTNUM;
  1855.     ptr = line;
  1856.         
  1857.     guessName[0] = '\0';
  1858.         while (*ptr)
  1859.         {
  1860.             if (ReadSubjectToken (thisTok = tok, &ptr) == NULL)
  1861.                 break;
  1862.         
  1863. //    NUMBERS
  1864.         if (numberMode != IGNORE_NUMBERS)
  1865.            if (isnumber (thisTok))
  1866.            {
  1867.             if (numberMode == SEEK_PARTNUM)
  1868.             {
  1869.                 thisDecode->sequence = atoi (thisTok);
  1870.                 thisDecode->seqConfidence = LOW;
  1871.  
  1872.                 if (ReadSubjectToken (next, &ptr) == NULL)
  1873.                     break;
  1874.                 if (!_stricmp (next, "/") ||
  1875.                     !_stricmp (next, "of"))
  1876.                 {
  1877.                     numberMode = SEEK_NUMPARTS;        
  1878.                     continue;
  1879.                 }
  1880.                 else    // no numParts immediately following
  1881.                     thisTok = next;    // process the next tok
  1882.             }
  1883.             else    // numberMode == SEEK_NUMPARTS
  1884.             {
  1885.                 thisNumBlocks = atoi (tok);
  1886.                 numberMode = IGNORE_NUMBERS;
  1887.                 thisDecode->seqConfidence = HIGH;
  1888.                     continue;
  1889.             }
  1890.            }
  1891.            else if (numberMode == SEEK_NUMPARTS)
  1892. //           We had '# of non#', a red herring, seek again
  1893.             numberMode == SEEK_PARTNUM;
  1894.             
  1895. //    WORDS
  1896.         // Prefer a word containing a dot for the ident (but not a period
  1897.         // at the end of a sentence
  1898.             if ((tmp = strchr (thisTok, '.')) && isalpha(*(tmp+1)))
  1899.             strcpy (thisDecode->ident, thisTok);
  1900.             else if (guessIdent)
  1901.             {
  1902.                 // skip if already have name w/ confidence
  1903.                 if (thisDecode->ident[0] == '\0')
  1904.             {
  1905.             // check if any threads have this token as name
  1906.                    if (SearchThreadNames (thisTok))
  1907.                     strcpy (thisDecode->ident, thisTok);
  1908.  
  1909.             // Save first word found for thread name
  1910.             // prefer ident not starting with 're'
  1911.                    else if (guessName[0] == '\0' || !_strnicmp(guessName, "re", 2))
  1912.                     strcpy (guessName, thisTok);
  1913.                 }
  1914.             }
  1915.     }
  1916.     if (guessIdent && thisDecode->ident[0] == '\0')
  1917.         strcpy (thisDecode->ident, guessName);
  1918.  
  1919. #ifdef DEBUG_DECODE
  1920.     sprintf(debug, "\nSubject header: name %s, part number %d (confidence %d), num parts %d", 
  1921.         thisDecode->ident, thisDecode->sequence, thisDecode->seqConfidence, thisNumBlocks);
  1922.     DebugLog();
  1923. #endif
  1924. }
  1925.  
  1926. char *
  1927. ReadSubjectToken (char *dest, char **ptr)
  1928. {
  1929.     int len;
  1930.     register int i;
  1931.     char *str = *ptr;
  1932.     
  1933.     if (*str == '\0')
  1934.         return ('\0');
  1935.         
  1936.     len = strcspn (str, " ()[]\\/:,\"'`{};\n\r");
  1937.  
  1938. /*    Ignore (skip) all of these delimiters except '/'
  1939.  *    Return '/' as a token of length 1
  1940.  */                      
  1941.     if (len == 0)
  1942.         if (*str == '/')
  1943.             len = 1;
  1944.         else
  1945.         {    // skip this delimiter
  1946.             (*ptr)++;
  1947.             return (ReadSubjectToken (dest, ptr));
  1948.         }
  1949.  
  1950.         for (i = 0; i < len; i++)
  1951.             dest[i] = tolower(str[i]);
  1952.         dest[len] = '\0';
  1953.  
  1954.     *ptr = str + len;    // increment line ptr    
  1955. }
  1956.  
  1957. BOOL
  1958. SearchThreadNames (char *name)
  1959. {
  1960.     register int i;
  1961.     int len;
  1962.     
  1963.     len = strlen (name);
  1964.  
  1965.     for (i = 0; i < numDecodeThreads; i++)
  1966.         if (!_strnicmp (name, threadList[i]->ident, len))
  1967.             return (TRUE);
  1968.  
  1969.     return (FALSE);
  1970. }
  1971.  
  1972. /* ParseAppSpecificLine
  1973.  * returns TRUE if it handles the line, else FALSE
  1974.  *
  1975.  * Example info lines handled by this function:
  1976.  *    part=n
  1977.  *    file=abc.def
  1978.  *    pfile=xyz.abc 
  1979.  *    Archive-name: fileident/part0n        // no extension included for filename
  1980.  *
  1981.  *     section N of uuencode 5.10 of file abcd.efg   by R.E.M.
  1982.  *    section n/N   file abcd.efg   [ Wincode v2.3 ]
  1983.  *    [ Section: n/N  File: abcd.efg  Encoder: Wincode v1.4 ]
  1984.  *    section n/N abcd.efg  [EnUU 2.1]
  1985.  *  abcd.efg    section  n/N   UUXFER ver 2.0 by David M. Read
  1986.  *    POST V2.0.0 abcd.efg (Part n/N)
  1987.  */
  1988. BOOL
  1989. ParseAppSpecificLine (TypCoded *thisDecode, char *line)
  1990. {
  1991.     char *orig, *ptr;
  1992.     int seq, num, len;
  1993.     float ver;
  1994.     char name[MAXINTERNALLINE];
  1995.     char copy[MAXINTERNALLINE];
  1996.     
  1997.        for (orig = line; *orig && isspace(*orig); orig++);    // skip leading spaces
  1998.     
  1999.     if (*orig == '\0')            // blank line (or all spaces)
  2000.             return (SUCCESS);
  2001.  
  2002.     len = min(MAXINTERNALLINE-1, strlen(orig));
  2003.     strncpy (copy, orig, len);    // make a lower-case copy
  2004.     copy[len] = '\0';
  2005.     strlwr(copy);
  2006.     
  2007.     if (!strncmp(orig, "BEGIN", 5))    // specifically comparing case-sensitive
  2008.     {
  2009.         ParseInfoLine(thisDecode, copy, FALSE);
  2010.         return (TRUE);
  2011.     }
  2012.  
  2013.     if (sscanf(copy, "file=%s", name) == 1)
  2014.     {
  2015.         strcpy (thisDecode->ident, name);
  2016.         return (TRUE);
  2017.     }
  2018.  
  2019.     if (*copy == 'p')    // info headers starting with 'p'
  2020.     {
  2021.         if (sscanf(copy, "part=%d", &seq) == 1)
  2022.         {
  2023.             thisDecode->sequence = seq;
  2024.             if (!thisDecode->seqConfidence)
  2025.                 thisDecode->seqConfidence = LOW; // still don't have number of parts
  2026.             return (TRUE);
  2027.         }
  2028.         if (sscanf(copy, "pfile=%s", name) == 1)
  2029.         {
  2030.             strcpy (thisDecode->ident, name);
  2031.             return (TRUE);
  2032.         }
  2033.         /* POST */
  2034.         if (sscanf (copy, "POST V%*s %s (Part %d/%d)", name, &seq, &num) == 3)
  2035.         {
  2036.             thisDecode->sequence = seq;
  2037.             thisNumBlocks = num;
  2038.             thisDecode->seqConfidence = HIGH;
  2039.             strcpy (thisDecode->ident, name);
  2040.             return (TRUE);
  2041.         }
  2042.         return (FALSE);    // started with 'p' but we didn't have a template
  2043.     }
  2044.  
  2045.     /* note some of these look for a version number, then don't use it.  the
  2046.        version number is scanned simply to add to our confidence that this is
  2047.        a valid info line.  we want it to be included in the count - so we know
  2048.        if the line fits the template (hence don't use %*f)
  2049.     */
  2050.  
  2051.     /* R.E.M., EnUU, and WinCode v2.x all start with "section " */
  2052.     if (!strncmp(copy, "section", 7))
  2053.     {
  2054.         ptr = ©[7];
  2055.         /* R.E.M. */
  2056.         if (sscanf (ptr, " %d of uuencode %f of file %s", &seq, &ver, name) == 3)
  2057.         {    
  2058.             thisDecode->sequence = seq;
  2059.             if (!thisDecode->seqConfidence)
  2060.                 thisDecode->seqConfidence = LOW; // still don't have number of parts
  2061.                     
  2062.             strcpy (thisDecode->ident, name);
  2063.             thisContentEncoding = CODE_UU;
  2064.             return (TRUE);
  2065.         }
  2066.          /* EnUU */
  2067.          if (sscanf (ptr, " %d/%d %s [EnUU %f]", &seq, &num, name, &ver) == 4)
  2068.         {
  2069.             thisDecode->sequence = seq;
  2070.             thisNumBlocks = num;
  2071.             thisDecode->seqConfidence = HIGH; 
  2072.             strcpy (thisDecode->ident, name);
  2073.             thisContentEncoding = CODE_UU;
  2074.             return (TRUE);
  2075.         }
  2076.         /* Wincode v2.x */
  2077.         if (sscanf (ptr, " %d/%d  file %s [ Wincode v%f ]", &seq, &num, name, &ver) == 4)
  2078.         {
  2079.             thisDecode->sequence = seq;
  2080.             thisNumBlocks = num;
  2081.             thisDecode->seqConfidence = HIGH; 
  2082.             strcpy (thisDecode->ident, name);
  2083.             return (TRUE);
  2084.         }
  2085.         return (FALSE);    // started with 'section' but we didn't have a template
  2086.     }
  2087.     /* Wincode v1.x */
  2088.     if (sscanf (copy, "[ section: %d/%d  File: %s  Encoder: Wincode v%f", &seq, &num, &ver) == 4)
  2089.     {
  2090.         thisDecode->sequence = seq;
  2091.         thisNumBlocks = num;
  2092.         thisDecode->seqConfidence = HIGH; 
  2093.         strcpy (thisDecode->ident, name);
  2094.         return (TRUE);
  2095.     }
  2096.  
  2097.     /* UUXFER */
  2098.     if (sscanf (copy, "%s section %d/%d  UUXFER ver %f", name, &seq, &num, &ver) == 4)
  2099.     {    
  2100.         thisDecode->sequence = seq;
  2101.         thisNumBlocks = num;
  2102.         thisDecode->seqConfidence = HIGH; 
  2103.         strcpy (thisDecode->ident, name);
  2104.         thisContentEncoding = CODE_UU;
  2105.         return (TRUE);
  2106.     }
  2107.  
  2108.     if (sscanf(copy, "archive-name: %[^/]/part%d", name, &seq) == 2)        // %[^/] reads a string up to a slash
  2109.     {
  2110.         strcpy (thisDecode->ident, name);
  2111.         thisDecode->sequence = seq;
  2112.         if (!thisDecode->seqConfidence)
  2113.             thisDecode->seqConfidence = LOW; // still don't have number of parts
  2114.         return (TRUE);
  2115.     }
  2116.  
  2117.     return (FALSE);
  2118. }
  2119. //-------------------------------------------------------------------------
  2120. void
  2121. ExecuteDecodedFile(int num, char *fileName)
  2122. {
  2123.     char ext[4];        // these are DOS specific...
  2124. //    char name[9];
  2125.     char association[MAXINTERNALLINE];
  2126.     char execute[MAXINTERNALLINE+MAXFILENAME];
  2127.     int len;
  2128.     unsigned int err;
  2129.     char *src, *dest, *src2;
  2130.     char mybuf[MAXINTERNALLINE];
  2131.  
  2132. #ifndef WIN32
  2133.     GetFileExtension (ext, fileName);
  2134.  
  2135.         if (!_stricmp (ext, "exe"))
  2136.             strcpy (execute, fileName);
  2137.     else
  2138.     // example association: doc=C:\WIN\WINWORD\winword.exe ^.doc
  2139.  
  2140.     if ((len = GetProfileString ("Extensions", (LPCSTR)ext, "", association, MAXINTERNALLINE)) != 0)
  2141.     {
  2142.       for (src = association, dest = execute; *src; src++)
  2143.       {
  2144.         if (*src == '^')
  2145.         {
  2146.             for (src2 = fileName; *src2 && *src2 != '.'; src2++)
  2147.                *(dest++) = *src2;
  2148.         }
  2149.         else
  2150.            *(dest++) = *src;
  2151.       }
  2152.       *dest = '\0';
  2153.         }
  2154.         else
  2155.         {
  2156.         sprintf(mybuf, "Cannot execute - no association for file type %s", ext);
  2157.         UpdateThreadStatus (num, mybuf);
  2158.         return;
  2159.     }
  2160.  
  2161. #else
  2162.         FindExecutable (fileName, ".", association);
  2163.     wsprintf (execute, "%s %s", association, fileName);
  2164. #endif
  2165.     if ((err = WinExec (execute, SW_SHOWNORMAL)) < 32)
  2166.     {
  2167.         sprintf(mybuf, "Error executing %s, error %u", execute, err);
  2168.         UpdateThreadStatus (num, mybuf);
  2169.     }
  2170.     else if (CodingStatusVerbose)
  2171.     {
  2172.         sprintf(mybuf, "Executed %s", execute);
  2173.         UpdateThreadStatus (num, mybuf);
  2174.     }
  2175. }
  2176. @
  2177.  
  2178.  
  2179. 1.11
  2180. log
  2181. @new coding-status window style.  optimized info-header parser.
  2182. general cleanup for 92.6
  2183. @
  2184. text
  2185. @d37 1
  2186. a37 1
  2187.  * $Id: wvcoding.c 1.10 1994/08/24 18:00:29 jcooper Exp $
  2188. d39 4
  2189. d139 1
  2190. a350 3
  2191.     int x, y, width, height;
  2192.                                                                                                              
  2193.                                                                                                              
  2194. d353 1
  2195. d356 14
  2196. a369 5
  2197.     // Create coding status window
  2198.     width = STATUSWIDTH;
  2199.     height = STATUSHEIGHT;
  2200.     x = (xScreen - width)/2;        // center it
  2201.     y = 1;
  2202. d371 2
  2203. a372 2
  2204.             WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_DLGFRAME,
  2205.             x, y, width, height,
  2206. d378 6
  2207. d385 1
  2208. a385 1
  2209. DestroyStatusArea ()
  2210. d387 3
  2211. a389 3
  2212.     DestroyCodedBlock (¤tCoded);
  2213.     DestroyWindow (hCodedBlockWnd);
  2214.     hCodedBlockWnd = (HWND)NULL;
  2215. d391 1
  2216. d393 10
  2217. a567 1
  2218.     int x, y, width, height;
  2219. d592 1
  2220. a592 11
  2221.     width = STATUSWIDTH;
  2222.     height = STATUSHEIGHT;
  2223.     x = (xScreen - width)/2;        // center it
  2224.     y = 1;
  2225.     hCodedBlockWnd = CreateWindowEx (WS_EX_DLGMODALFRAME, "WinVnBlockCoding", "Block Decoding Status",
  2226.             WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_DLGFRAME,
  2227.             x, y, width, height,
  2228.             (HWND)NULL, (HMENU)NULL, hInst, (void far *)NULL);
  2229.  
  2230.     SetHandleBkBrush (hCodedBlockWnd, hStatusBackgroundBrush); 
  2231.     ShowWindow (hCodedBlockWnd, SW_SHOWNORMAL);
  2232. d595 1
  2233. a692 21
  2234.  *    Adds text to a thread coding status block, and refreshes
  2235.  *    the thread status window
  2236.  */    
  2237. void
  2238. UpdateThreadStatus (int num, char *str)
  2239. {
  2240.     AddLineToTextBlock (threadList[num]->statusText, str);
  2241.     InvalidateRect (threadList[num]->statusText->hTextWnd, NULL, FALSE);
  2242.     UpdateWindow (threadList[num]->statusText->hTextWnd);
  2243. }
  2244.  
  2245. /* ------------------------------------------------------------------------
  2246.  *    Refreshes the block status window
  2247.  */    
  2248. void
  2249. UpdateBlockStatus ()
  2250. {
  2251.     InvalidateRect (hCodedBlockWnd, NULL, FALSE);
  2252.     UpdateWindow (hCodedBlockWnd);
  2253. }
  2254. /* ------------------------------------------------------------------------
  2255. d706 3
  2256. d764 1
  2257. a764 1
  2258.            int x, y, width, height;
  2259. d816 1
  2260. a816 1
  2261.             if (CodingStatusVerbose || numStatusTexts == 0)
  2262. d821 1
  2263. a821 1
  2264.                    if (numStatusTexts + 1 > MAX_DECODE_THREADS);
  2265. d824 1
  2266. a824 1
  2267.                    codingStatusText[numStatusTexts++] = threadList[num]->statusText;
  2268. a825 5
  2269.            width = (int)(xScreen * 1/2);
  2270.            x = (numStatusTexts * StatusCharWidth) % (int) (xScreen * 3/4);
  2271.            height = (int) (yScreen * 1/2) - (1 * StatusLineHeight);
  2272.            y = (int) (yScreen * 1/4) + (numStatusTexts * StatusLineHeight) % (int)(yScreen * 3/4);
  2273.  
  2274. d831 8
  2275. d857 1
  2276. a857 1
  2277.            threadList[num]->statusText = codingStatusText[0];
  2278. d1024 1
  2279. a1024 1
  2280.                     threadList[num]->name, threadList[num]->totalBytes, threadList[num]->dosFileName);
  2281. d1109 1
  2282. a1109 1
  2283.                 threadList[num]->name, threadList[num]->totalBytes, threadList[num]->dosFileName);
  2284. @
  2285.  
  2286.  
  2287. 1.10
  2288. log
  2289. @misc encoding/decoding changes
  2290. @
  2291. text
  2292. @d37 1
  2293. a37 1
  2294.  * $Id: wvcoding.c 1.9 1994/08/11 21:03:19 rushing Exp $
  2295. d39 3
  2296. a66 2
  2297. #include <stdio.h>
  2298. #include <stdlib.h>
  2299. d69 3
  2300. d73 2
  2301. a75 2
  2302. #include "wvglob.h"
  2303. #include "winvn.h"
  2304. d217 2
  2305. d220 1
  2306. d223 5
  2307. a227 1
  2308.             CompleteThisDecode ();
  2309. d271 2
  2310. d274 2
  2311. d278 5
  2312. a282 1
  2313.             CompleteThisDecode ();
  2314. a290 2
  2315.     GlobalUnlock (BlockPtr->hCurBlock);
  2316.  
  2317. d295 1
  2318. d318 1
  2319. a318 1
  2320.     if (AskForNewFileName (hParentWnd, fileName, "") != FAIL)
  2321. d358 2
  2322. a359 2
  2323.     hCodedBlockWnd = CreateWindow ("WinVnBlockCoding", "Block Encoding Status",
  2324.             WS_OVERLAPPEDWINDOW|WS_MINIMIZEBOX,
  2325. d568 2
  2326. a569 2
  2327.     hCodedBlockWnd = CreateWindow ("WinVnBlockCoding", "Block Decoding Status",
  2328.             WS_OVERLAPPEDWINDOW|WS_MINIMIZEBOX,
  2329. d757 1
  2330. a757 1
  2331. BOOL
  2332. d1071 1
  2333. a1071 1
  2334.                 DestroyCodedBlock (&(threadList[num]->codedBlockList[0]));
  2335. d1097 1
  2336. d1111 1
  2337. d1216 4
  2338. a1219 2
  2339.         if (AskForNewFileName (hCodedBlockWnd, actualFileName, DecodePathName) == FAIL)
  2340.             return (FAIL);                                  
  2341. d1273 1
  2342. a1273 1
  2343.     if (strlen(line) < 2)    /* skip over short/blank lines */
  2344. d1283 5
  2345. a1287 2
  2346.     // encoded UU/XX/Custom data always starts with line 
  2347.     // like 'begin <mode> <file-name>'
  2348. d1316 1
  2349. a1316 1
  2350.          else if (!_strnicmp(line, "table", 5))
  2351. d1360 5
  2352. a1364 3
  2353.                 sprintf (str, "Invalid decoding table in block.  Duplicate character %c.",  i);
  2354.                 MessageBox (hCodedBlockWnd, str, "Invalid coding table", MB_OK);
  2355.                 return (FAIL);
  2356. d1366 2
  2357. a1367 1
  2358.             thisContentEncoding = CODE_CUSTOM;
  2359. a1432 1
  2360.     numEncoded = strlen(line);
  2361. d1442 1
  2362. a1442 1
  2363.     // these are 4-to-3 decodings which have the line lengtrh encoded
  2364. d1445 1
  2365. d1450 1
  2366. d1484 1
  2367. a1484 1
  2368.     if (AddDataToBlock (currentCoded, outLine, numDecoded) == FAIL)
  2369. d1890 1
  2370. a1890 1
  2371.         
  2372. d1894 6
  2373. a1899 1
  2374.  * Example application lines handled by this function:
  2375. d1902 1
  2376. d1904 1
  2377. a1904 1
  2378.  *      abcd.efg    section  n/N   UUXFER ver 2.0 by David M. Read
  2379. a1905 4
  2380.  *    part=n
  2381.  *    file=abc.def
  2382.  *    pfile=xyz.abc 
  2383.  *    Archive-name: fileident/part0n        // no extension included for filename
  2384. d1910 3
  2385. a1912 2
  2386.     char *orig;
  2387.     int seq, num;
  2388. d1918 1
  2389. a1918 1
  2390.     if (*orig == '\0')            // blank line (all spaces)
  2391. d1920 5
  2392. d1926 1
  2393. a1926 5
  2394.     /* note most application keywords will be compared case-sensitively
  2395.      * (using orig), but then all following info-gathering will be 
  2396.      * case-insensitive (using copy) 
  2397.      */
  2398.     if (sscanf(orig, "part=%d", &seq) == 1)
  2399. d1928 1
  2400. a1928 3
  2401.         thisDecode->sequence = seq;
  2402.         if (!thisDecode->seqConfidence)
  2403.             thisDecode->seqConfidence = LOW; // still don't have number of parts
  2404. d1931 2
  2405. a1932 1
  2406.     if (sscanf(orig, "file=%s", name) == 1)
  2407. a1936 13
  2408.     if (sscanf(orig, "pfile=%s", name) == 1)
  2409.     {
  2410.         strcpy (thisDecode->ident, name);
  2411.         return (TRUE);
  2412.     }
  2413.     if (sscanf(orig, "Archive-name: %[^/]/part%d", name, &seq) == 2)        // %[^/] reads a string up to a slash
  2414.     {
  2415.         strcpy (thisDecode->ident, name);
  2416.         thisDecode->sequence = seq;
  2417.         if (!thisDecode->seqConfidence)
  2418.             thisDecode->seqConfidence = LOW; // still don't have number of parts
  2419.         return (TRUE);
  2420.     }
  2421. d1938 1
  2422. a1938 5
  2423.     strncpy (copy, orig, MAXINTERNALLINE-1);
  2424.     copy[MAXINTERNALLINE-1] = '\0';
  2425.     AnsiLowerBuff ((LPSTR)copy, (UINT)strlen (copy));    // make a lower-case copy
  2426.  
  2427.     if (strstr(orig, "R.E.M."))
  2428. d1940 2
  2429. a1941 2
  2430.         if (sscanf (copy, "section %d of uuencode %*f of file %s", &seq, name) == 2)
  2431.         {    
  2432. d1945 4
  2433. a1948 1
  2434.                 
  2435. a1949 1
  2436.             thisContentEncoding = CODE_UU;
  2437. d1952 3
  2438. a1954 5
  2439.     }
  2440.     if (strstr(orig, "UUXFER"))
  2441.     {
  2442.         if (sscanf (copy, "%s section %d/%d", name, &seq, &num) == 3)
  2443.         {    
  2444. d1957 1
  2445. a1957 1
  2446.             thisDecode->seqConfidence = HIGH; 
  2447. a1958 1
  2448.             thisContentEncoding = CODE_UU;
  2449. d1961 1
  2450. d1963 9
  2451. a1971 1
  2452.     if (!strncmp(orig, "BEGIN", 5))
  2453. d1973 4
  2454. a1976 7
  2455.         ParseInfoLine(thisDecode, copy, FALSE);
  2456.         return (TRUE);
  2457.     }
  2458.     if (strstr(orig, "Wincode"))
  2459.     {
  2460.         if (sscanf (copy, "section %d/%d   file %s", &seq, &num, name) == 3)
  2461.         {
  2462. d1978 3
  2463. a1980 2
  2464.             thisNumBlocks = num;
  2465.             thisDecode->seqConfidence = HIGH; 
  2466. d1982 1
  2467. d1985 2
  2468. a1986 4
  2469.     }
  2470.      if (strstr(orig, "EnUU"))
  2471.     {
  2472.         if (sscanf (copy, "section %d/%d %s", &seq, &num, name) == 3)
  2473. d1995 2
  2474. a1996 4
  2475.     }
  2476.     if (!strncmp(orig, "POST", 4))
  2477.     {
  2478.         if (sscanf (copy, "POST V%*s %s (Part %d/%d)", name, &seq, &num) == 3)
  2479. d2000 1
  2480. a2000 1
  2481.             thisDecode->seqConfidence = HIGH;
  2482. d2004 30
  2483. @
  2484.  
  2485.  
  2486. 1.9
  2487. log
  2488. @FindExecutable fix for NT
  2489. @
  2490. text
  2491. @d37 1
  2492. a37 1
  2493.  * $Id: wvcoding.c 1.8 1994/08/11 20:16:25 rushing Exp $
  2494. d39 3
  2495. d116 1
  2496. a116 1
  2497. void    DestroyCodedBlock (TypCoded *thisCoded);
  2498. d220 1
  2499. a220 1
  2500.                 return;
  2501. d351 1
  2502. a351 1
  2503.     DestroyCodedBlock (currentCoded);
  2504. d625 1
  2505. a625 1
  2506.     TypCoded *thisCoded;
  2507. d691 1
  2508. a691 1
  2509.         DestroyCodedBlock (threadList[num]->codedBlockList[i]);
  2510. d704 1
  2511. a704 1
  2512.  *    Free the huge data
  2513. d707 1
  2514. a707 1
  2515. DestroyCodedBlock (TypCoded *thisCoded)
  2516. a708 1
  2517.     
  2518. d710 1
  2519. a710 1
  2520.     sprintf(debug, "\nDestroying block sequence %d", thisCoded->sequence);
  2521. d713 3
  2522. a715 2
  2523.     GlobalFreePtr (thisCoded->data);
  2524.     GlobalFreePtr (thisCoded);
  2525. d844 3
  2526. a846 3
  2527.     if (threadList[num]->contentType[0] == '\0')
  2528.         strcpy (threadList[num]->contentType, thisContentType);
  2529.     if (threadList[num]->expectedNumBlocks == 0)
  2530. d988 1
  2531. a988 1
  2532.         DestroyCodedBlock (currentCoded);
  2533. d1053 1
  2534. a1053 1
  2535.                 DestroyCodedBlock (threadList[num]->codedBlockList[0]);
  2536. d1113 1
  2537. a1113 1
  2538.     DestroyCodedBlock (threadList[num]->codedBlockList[0]);
  2539. d1382 2
  2540. d1604 1
  2541. a1604 1
  2542.     for (i = 0; i < dataLen; i++)
  2543. d1869 1
  2544. d1873 2
  2545. a1874 1
  2546.  *    pfile=xyz.abc
  2547. d1879 1
  2548. a1879 1
  2549.     char *orig, *ptr;
  2550. a1901 3
  2551.         if ((ptr = strpbrk(name, " \n\t\r\f")))    
  2552.             *ptr = '\0';
  2553.  
  2554. d1907 5
  2555. a1911 3
  2556.         if ((ptr = strpbrk(name, " \n\t\r\f")))    
  2557.             *ptr = '\0';
  2558.  
  2559. d1913 3
  2560. d1932 13
  2561. d1972 1
  2562. d1998 2
  2563. a1999 1
  2564.     int len, err;
  2565. d2038 1
  2566. a2038 1
  2567.         sprintf(mybuf, "Error executing %s, error %d", execute, err);
  2568. @
  2569.  
  2570.  
  2571. 1.8
  2572. log
  2573. @bug fix
  2574. @
  2575. text
  2576. @d37 1
  2577. a37 1
  2578.  * $Id: wvcoding.c 1.6 1994/07/25 20:05:13 jcooper Exp $
  2579. d39 3
  2580. d1977 1
  2581. a1977 1
  2582.     char mybuf[MAXINTERNALLINE];    
  2583. d1979 1
  2584. d1986 1
  2585. a1986 1
  2586.         
  2587. d2001 1
  2588. a2001 1
  2589.         else 
  2590. d2004 1
  2591. a2004 1
  2592.         UpdateThreadStatus (num, mybuf);            
  2593. d2008 4
  2594. d2015 1
  2595. a2015 1
  2596.         UpdateThreadStatus (num, mybuf);            
  2597. d2020 2
  2598. a2021 2
  2599.         UpdateThreadStatus (num, mybuf);            
  2600.     }    
  2601. @
  2602.  
  2603.  
  2604. 1.7
  2605. log
  2606. @Enhancements to Mime and article encoding/encoding
  2607. @
  2608. text
  2609. @a1814 1
  2610.     
  2611. a1853 1
  2612.  
  2613. d1874 5
  2614. a1878 2
  2615.        for (orig = line; *orig && isspace(*orig); *orig++);    // skip leading spaces
  2616.  
  2617. @
  2618.  
  2619.  
  2620. 1.6
  2621. log
  2622. @execution of decoded files
  2623. @
  2624. text
  2625. @d30 1
  2626. a30 1
  2627.  * Author: John S. Cooper (jcoop@@apl.com)                           *
  2628. a34 1
  2629.  * Please do not use this code for profit or damage                 *
  2630. d37 1
  2631. a37 1
  2632.  * $Id: wvcoding.c 1.5 1994/05/23 18:36:00 jcooper Exp $
  2633. d39 3
  2634. d101 1
  2635. a101 1
  2636. char     thisBlockIdent[MAXFILENAME], prevBlockIdent[MAXFILENAME];
  2637. d117 2
  2638. a118 2
  2639. void    ParseSubjectLine (TypCoded *thisDecode, char *line);
  2640. void    ParseREMLine (TypCoded *thisDecode, char *line);
  2641. d139 1
  2642. a139 1
  2643. char     debug[255];
  2644. d294 1
  2645. a294 1
  2646.     if (AskForNewFileName (hParentWnd, fileName, ""))
  2647. a529 1
  2648.     thisBlockIdent[0] = '\0';
  2649. d599 1
  2650. a599 1
  2651.             sprintf (mybuf, "%sCompleteness confidence is pretty mediocre, written total size %ld", name, threadList[0]->totalBytes);
  2652. d607 1
  2653. d816 1
  2654. a816 1
  2655.       
  2656. d907 1
  2657. d1042 1
  2658. a1042 1
  2659.           currentCoded->seqConfidence == HIGH)
  2660. a1082 3
  2661.         if (ExecuteDecodedFiles)
  2662.             ExecuteDecodedFile(num, threadList[num]->dosFileName);
  2663.  
  2664. d1135 3
  2665. d1245 1
  2666. a1245 1
  2667.     if (strlen(line) < 3)    /* skip over short/blank lines */
  2668. d1280 5
  2669. a1284 3
  2670.              ParseSubjectLine (thisDecode, &line[8]);
  2671.          else if (!DumbDecode && strstr(line, "R.E.M."))
  2672.              ParseREMLine (thisDecode, line);
  2673. a1371 1
  2674.             thisBlockIdent[0] = '\0';            
  2675. d1683 3
  2676. a1685 2
  2677.  *    Search through a subject line (the Subject: part has already been 
  2678.  *    removed).
  2679. d1687 5
  2680. a1691 2
  2681.  *    Generate an identifier based on the subejct, preferably based on the
  2682.  *    actual file name
  2683. d1695 1
  2684. a1695 1
  2685.  *    Common styles which this function deals with:
  2686. d1705 7
  2687. d1729 1
  2688. a1729 1
  2689. ParseSubjectLine (TypCoded *thisDecode, char *line)
  2690. a1738 2
  2691.     thisNumBlocks = -1;
  2692.     thisBlockIdent[0] = '\0';
  2693. d1782 2
  2694. a1783 1
  2695.             else
  2696. d1796 1
  2697. d1798 1
  2698. a1798 2
  2699.  
  2700.     if (thisDecode->ident[0] == '\0')
  2701. d1823 1
  2702. a1823 1
  2703.  */
  2704. d1856 14
  2705. a1869 3
  2706. // example: "section N of uuencode 5.10 of file abcd.gef   by R.E.M."
  2707. void
  2708. ParseREMLine (TypCoded *thisDecode, char *line)
  2709. d1871 2
  2710. a1872 2
  2711.     char *ptr;
  2712.     int seq;
  2713. d1874 1
  2714. d1876 84
  2715. a1959 5
  2716.     AnsiLowerBuff ((LPSTR)line, (UINT)strlen(line));
  2717.        ptr = line;
  2718.        while (*ptr && isspace(*ptr)) *ptr++;
  2719.     if (sscanf (ptr, "section %d of uuencode %*f of file %s", &seq, name) != 2)
  2720.         return;
  2721. d1961 1
  2722. a1961 5
  2723.     thisDecode->sequence = seq;
  2724.     if (!thisDecode->seqConfidence)
  2725.         thisDecode->seqConfidence = LOW; // still don't have number of parts
  2726.         
  2727.     strcpy (thisDecode->ident, name);
  2728. d1998 1
  2729. a1998 1
  2730.         sprintf(mybuf, "No association for file type %s", ext);
  2731. d2005 1
  2732. a2005 1
  2733.         sprintf(mybuf, "Error running %s, error %d", execute, err);
  2734. d2010 1
  2735. a2010 1
  2736.         sprintf(mybuf, "Sucessfully executed %s", execute);
  2737. @
  2738.  
  2739.  
  2740. 1.5
  2741. log
  2742. @new attach code, session [dis]connect
  2743. @
  2744. text
  2745. @d38 1
  2746. a38 1
  2747.  * $Id: wvcoding.c 1.4 1994/03/01 19:14:22 rushing Exp $
  2748. d40 3
  2749. d116 1
  2750. d131 2
  2751. d278 10
  2752. a287 8
  2753.     register unsigned long i;
  2754.     char fileName[MAXFILENAME];
  2755.         OFSTRUCT outFileStruct;
  2756.         HFILE hAttachFile;
  2757.         TypTextBlock *encodeData;
  2758.  
  2759.     if ((encodeData = InitTextBlock (hParentWnd)) == NULL)
  2760.         return;
  2761. d289 2
  2762. a290 6
  2763.     CreateStatusArea(hParentWnd);
  2764.         strcpy (currentCoded->ident, inFile);    // status window info
  2765.  
  2766.     if (Encode (encodeData, inFile, ADD_TO_FILE) == FAIL)
  2767.         return;
  2768.  
  2769. d292 1
  2770. a292 4
  2771.     if (AskForNewFileName (hParentWnd, fileName, "") == FAIL)
  2772.         return;
  2773.         
  2774.     if ((hAttachFile = OpenFile ((char far *) fileName, &outFileStruct, OF_CREATE)) < 0)
  2775. d294 1
  2776. d296 11
  2777. a306 9
  2778.         return;
  2779.            }
  2780.     for (i = 0; i < encodeData->numLines; i++)
  2781.         _lwrite (hAttachFile, TextBlockLine (encodeData, i), lstrlen(TextBlockLine (encodeData, i)));
  2782.     
  2783.     _lclose (hAttachFile);
  2784.     FreeTextBlock (encodeData);
  2785.     DestroyCodedBlock (currentCoded);    // free status blk (created in Encode)
  2786.     DestroyWindow (hCodedBlockWnd);        // close status window
  2787. d321 2
  2788. a322 1
  2789.  
  2790. d1080 3
  2791. d1159 6
  2792. a1164 1
  2793.            sprintf (actualFileName, "%s\\%s", DecodePathName, threadList[num]->dosFileName);
  2794. d1180 6
  2795. a1185 1
  2796.             sprintf (actualFileName, "%s\\%s", DecodePathName, threadList[num]->dosFileName);
  2797. d1188 1
  2798. a1188 1
  2799.             return (FAIL);
  2800. d1278 2
  2801. d1841 21
  2802. a1862 1
  2803. #ifdef OLD
  2804. d1864 1
  2805. a1864 1
  2806. OldParseSubjectLine (TypCoded *thisDecode, char *line)
  2807. d1866 23
  2808. a1888 50
  2809.     char *beg, *end;
  2810.     char temp[30];
  2811.     int len, thisBlockPart;
  2812.     
  2813.     beg = line;
  2814.     /* skip to beginning of filename */
  2815.     while (!isalnum(*beg)) beg++;    
  2816.     
  2817.     if ((end = strpbrk (beg, " ([:"))) == NULL)
  2818.     {
  2819.         thisBlockPart = -1;
  2820.         len = min (strlen (beg), MAXFILENAME-1);
  2821.         strncpy (thisBlockName, beg, len);
  2822.         thisBlockName[len] = '\0';
  2823.     }        
  2824.     else 
  2825.     { 
  2826.         len = min (end-beg, MAXFILENAME-1);
  2827.         strncpy (thisBlockName, beg,len);
  2828.         thisBlockName[len] = '\0';
  2829.         RemoveTrailingWhiteSpace(thisBlockName);
  2830.  
  2831.         /* skip delimiter, then skip to part number */
  2832.         for (beg = end + 1; *beg != '\0' && !isdigit(*beg); beg++);
  2833.         if (*beg == '\0')
  2834.             thisBlockPart = -1;
  2835.                 else {
  2836.                     /* find end of number, then put number in temp */
  2837.             for (end = beg + 1;  *end != '\0' && isdigit(*end); end++);
  2838.             strncpy (temp, beg, end-beg);
  2839.             temp[end-beg] = '\0';
  2840.             
  2841.             if ((thisBlockPart = atoi (temp)) == 0)
  2842.                 thisBlockPart = -1;
  2843.             
  2844.             /* skip to next number (num parts) */
  2845.             for (beg = end + 1; *beg != '\0' && !isdigit(*beg); beg++);
  2846.             if (*beg == '\0')
  2847.                 thisNumBlocks = -1;
  2848.             else {
  2849.                         /* find end of number, then put number in temp */
  2850.                 for (end = beg + 1;  *end != '\0' && isdigit(*end); end++);
  2851.                 strncpy (temp, beg, end-beg);
  2852.                 temp[end-beg] = '\0';
  2853.  
  2854.                 if ((thisNumBlocks = atoi (temp)) == 0)
  2855.                     thisNumBlocks = -1;
  2856.                 else if (thisBlockPart > thisNumBlocks)
  2857.                     thisBlockPart = -1;
  2858.             }
  2859. d1890 10
  2860. a1900 1
  2861.     strcpy (thisDecode->name, thisBlockName);
  2862. d1902 10
  2863. a1911 3
  2864.     thisDecode->sequence = thisBlockPart;
  2865.     SendMessage (hCodedBlockWnd, WM_PAINT, STATUS_NAME|STATUS_SEQUENCE, (LPARAM)NULL);
  2866.     InvalidateRect (hCodedBlockWnd, NULL, FALSE);
  2867. a1912 2
  2868.  
  2869. #endif
  2870. @
  2871.  
  2872.  
  2873. 1.4
  2874. log
  2875. @ifdef'd the DEBUG info
  2876. @
  2877. text
  2878. @d38 1
  2879. a38 1
  2880.  * $Id: wvcoding.c 1.3 1994/02/24 21:28:04 jcoop Exp $
  2881. d40 3
  2882. d284 2
  2883. a285 1
  2884.     Encode (encodeData, inFile, ADD_TO_FILE);
  2885. d349 1
  2886. a349 1
  2887. void
  2888. d362 1
  2889. a362 1
  2890.     switch (EncodingType)
  2891. d377 2
  2892. a378 1
  2893.         AddEndedLineToTextBlock (textBlock, "table", mode);
  2894. d381 2
  2895. a382 1
  2896.         AddEndedLineToTextBlock (textBlock, str, mode);
  2897. d384 2
  2898. a385 1
  2899.         AddEndedLineToTextBlock (textBlock, str, mode);
  2900. d390 1
  2901. a390 1
  2902.     switch (EncodingType)
  2903. d400 2
  2904. a401 1
  2905.         AddEndedLineToTextBlock (textBlock, outLine, mode);
  2906. d422 1
  2907. a422 1
  2908.             if (EncodingType != CODE_BASE64)
  2909. d429 2
  2910. a430 1
  2911.         AddEndedLineToTextBlock (textBlock, outLine, mode);
  2912. d437 1
  2913. a437 1
  2914.     switch (EncodingType)
  2915. d445 2
  2916. a446 1
  2917.         AddEndedLineToTextBlock (textBlock, outLine, mode);
  2918. d449 2
  2919. a450 1
  2920.         AddEndedLineToTextBlock (textBlock, outLine, mode);
  2921. d456 1
  2922. d482 1
  2923. a482 1
  2924.         if (EncodingType == CODE_BASE64)
  2925. d490 1
  2926. a490 1
  2927.         if (EncodingType == CODE_BASE64)
  2928. @
  2929.  
  2930.  
  2931. 1.3
  2932. log
  2933. @jcoop changes.
  2934. @
  2935. text
  2936. @d38 1
  2937. a38 1
  2938.  * $Id: wvcoding.c 1.2 1994/02/09 18:01:08 cnolan Exp $
  2939. d40 3
  2940. d58 2
  2941. d63 1
  2942. @
  2943.  
  2944.  
  2945. 1.2
  2946. log
  2947. @cnolan 90.2 changes
  2948. @
  2949. text
  2950. @d38 1
  2951. a38 1
  2952.  * $Id: wvcoding.c 1.1 1994/01/18 09:54:20 jcoop Exp $
  2953. d40 3
  2954. d55 3
  2955. a57 3
  2956. //#define DEBUG_MAP
  2957. //#define DEBUG_MEM
  2958. //#define DEBUG_DECODE
  2959. d64 1
  2960. a64 1
  2961. #define ENCODE_LINE_LEN    45    
  2962. d68 1
  2963. a68 1
  2964. static char
  2965. d70 1
  2966. a70 1
  2967. static char
  2968. d72 1
  2969. a72 1
  2970. static char
  2971. d74 2
  2972. a75 3
  2973. char    xxMap[128], uuMap[128], thisMap[128];
  2974. char    *codingMap, *codingTable;
  2975. char    thisTable[CODINGTABLESIZE], prevTable[CODINGTABLESIZE];
  2976. a81 1
  2977. BOOL    customTable;            // = TRUE if found custom table
  2978. a83 1
  2979. int    thisContentEncoding;
  2980. d85 2
  2981. d92 1
  2982. a92 1
  2983. void    EncodeUnit (unsigned char *out, unsigned char *in);
  2984. d115 1
  2985. a115 1
  2986. BOOL    ThreadTable (char *dest, char *name);
  2987. d166 1
  2988. a166 1
  2989.         char mybuf[MAXINTERNALLINE], fileName[MAXFILENAME];
  2990. d183 1
  2991. a183 1
  2992.            while (fgets(mybuf, MAXINTERNALLINE, DecodeFile) != NULL)
  2993. d185 3
  2994. d200 2
  2995. d313 2
  2996. a314 2
  2997.     width = 75 * StatusCharWidth;
  2998.     height = 10 * StatusLineHeight;
  2999. d344 2
  3000. a345 1
  3001.     unsigned char inBuf[ENCODE_LINE_LEN];
  3002. d354 1
  3003. a354 1
  3004.     case ENCODE_BASE64:    
  3005. d357 2
  3006. a358 2
  3007.     case ENCODE_UU:
  3008.         codingTable = uuTable;;
  3009. d360 1
  3010. a360 1
  3011.     case ENCODE_XX:
  3012. d362 1
  3013. a362 1
  3014.         codingTable = xxTable;;
  3015. d364 1
  3016. a364 1
  3017.     case ENCODE_CUSTOM:
  3018. d379 5
  3019. a383 3
  3020.     case ENCODE_UU:
  3021.     case ENCODE_XX:
  3022.     case ENCODE_CUSTOM:
  3023. d390 1
  3024. a390 1
  3025.             outLine[0] = codingTable[ENCODE_LINE_LEN];
  3026. d393 3
  3027. a395 1
  3028.     case ENCODE_BASE64:
  3029. d398 1
  3030. a398 1
  3031.     lineLen = ENCODE_LINE_LEN;
  3032. d407 7
  3033. a413 2
  3034.             outLine[0] = codingTable[numRead];
  3035.  
  3036. d424 3
  3037. a426 3
  3038.     case ENCODE_UU:
  3039.     case ENCODE_XX:
  3040.     case ENCODE_CUSTOM:
  3041. d451 1
  3042. a451 1
  3043.         EncodeUnit (&outLine[j], &line[i]);
  3044. d458 1
  3045. a458 1
  3046. EncodeUnit (unsigned char *out, unsigned char *in)
  3047. d462 7
  3048. d470 7
  3049. a494 3
  3050. //    Note, XX table is hard coded in declarations for simplicity
  3051.     CreateCodingMap(uuMap, uuTable);
  3052.     CreateCodingMap(xxMap, xxTable);
  3053. d507 3
  3054. a509 2
  3055.     thisTable[0] = '\0';
  3056.     prevTable[0] = '\0';
  3057. d516 2
  3058. a517 2
  3059.     width = 75 * StatusCharWidth;
  3060.     height = 10 * StatusLineHeight;
  3061. d561 2
  3062. a562 1
  3063.         else if (!threadList[0]->codedBlockList[threadList[0]->numBlocks-1]->endFlag)
  3064. a616 1
  3065. //    thisCoded->altName[0] = '\0';
  3066. a618 1
  3067.         customTable = FALSE;
  3068. d757 3
  3069. a759 1
  3070.         strncpy (threadList[num]->codingTable, thisTable, CODINGTABLESIZE);
  3071. d989 2
  3072. a990 5
  3073. /* Save this coding table, and blank out the current table
  3074.  * This will cause the next block to start decoding w/ a clean slate
  3075.  */
  3076.     strncpy (prevTable, thisTable, CODINGTABLESIZE);
  3077.     thisTable[0] = '\0';
  3078. d1142 2
  3079. a1143 1
  3080.  
  3081. d1146 1
  3082. a1146 1
  3083.         else
  3084. d1148 2
  3085. a1149 1
  3086.         sprintf (actualFileName, "%s\\%s", DecodePathName, threadList[num]->dosFileName);
  3087. d1216 2
  3088. a1217 1
  3089. /* encoded data always starts with line like 'begin <mode> <file-name>' */
  3090. d1237 2
  3091. a1238 2
  3092. /* Check for keywords in the non-data lines which may aid in describing the line length,
  3093.  * the destination file for this data, the sequence, etc
  3094. d1273 1
  3095. a1273 1
  3096.         memmove ((thisTable + table_count * 32), line, 32);
  3097. d1278 1
  3098. a1278 1
  3099.             strncpy (str, thisTable, 64);
  3100. d1284 1
  3101. a1284 1
  3102.             if (i = CreateCodingMap (thisMap, thisTable) != -1)
  3103. d1290 1
  3104. a1290 2
  3105.             codingMap = thisMap;
  3106.             customTable = TRUE;
  3107. d1301 2
  3108. a1302 1
  3109.         if (!_strnicmp (line, "end", 3) || !IsDataLine(line))
  3110. d1311 1
  3111. a1311 1
  3112.  * data yet (< about a line's worth), then the line which gave us the table
  3113. d1315 1
  3114. a1315 1
  3115.  * this line.  Note if we have a customTable, then we trust it.
  3116. d1317 1
  3117. a1317 1
  3118.             if (!customTable && thisDecode->numBytes < 80)
  3119. d1320 1
  3120. a1320 1
  3121.                 thisTable[0] = '\0';
  3122. d1346 1
  3123. a1346 1
  3124.  * Decode a data line
  3125. d1350 48
  3126. a1397 14
  3127.     register unsigned int i, j;
  3128.     unsigned int charCount, numDecoded, checkSum;
  3129.     unsigned char buf[4], outLine[120];
  3130.     
  3131.     checkSum = charCount = codingMap[line[0]];    // count is # of chars after decoding
  3132.     for (i = 1, numDecoded=0; numDecoded < charCount;)
  3133.     {
  3134. /* Get the next group of four characters */
  3135.         for (j = 0; j < 4; j++, i++)
  3136.             checkSum += (buf[j] = codingMap[line[i]]); 
  3137.         
  3138.             outLine[numDecoded++] = buf[0]<<2|buf[1]>>4;
  3139.         outLine[numDecoded++] = buf[1]<<4|buf[2]>>2;
  3140.         outLine[numDecoded++] = buf[2]<<6|buf[3];
  3141. d1399 8
  3142. a1406 2
  3143.     if (AddDataToBlock (currentCoded, outLine, numDecoded) == FAIL)
  3144.         return (FAIL);
  3145. d1415 1
  3146. a1415 1
  3147.     return (SUCCESS);
  3148. a1428 1
  3149. //            thisDecode->maxBytes *= 2L;    // must always be a power of 2 
  3150. a1443 2
  3151.  *    If this is a new block (thisTable is empty), auto-determine what
  3152.  *    encoding scheme is used
  3153. d1448 1
  3154. a1448 1
  3155.     if (thisTable[0] == '\0')
  3156. d1450 4
  3157. a1453 3
  3158. /* If this block has same ident as prev, use same decode table
  3159.  * If diff name, use table stored in thread w/ same name, or if none 
  3160.  * try to auto-detect
  3161. d1458 1
  3162. a1458 3
  3163.             strncpy (thisTable, prevTable, CODINGTABLESIZE);
  3164.             CreateCodingMap (thisMap, thisTable);
  3165.             codingMap = thisMap;
  3166. d1465 1
  3167. a1465 1
  3168.             if (ThreadTable (thisTable, currentCoded->ident) == SUCCESS)
  3169. d1467 2
  3170. a1468 2
  3171.                 CreateCodingMap (thisMap, thisTable);
  3172.                 codingMap = thisMap;
  3173. d1476 1
  3174. a1476 1
  3175.                 codingMap = uuMap;
  3176. a1482 1
  3177.                     strncpy (thisTable, uuTable, CODINGTABLESIZE);
  3178. d1485 1
  3179. a1485 1
  3180.                 codingMap = xxMap;
  3181. a1491 1
  3182.                     strncpy (thisTable, xxTable, CODINGTABLESIZE);
  3183. d1494 10
  3184. d1513 11
  3185. a1523 2
  3186.     unsigned int expectedLineLen, dataLen, lineLen;
  3187.     register unsigned int i;
  3188. d1525 2
  3189. a1526 2
  3190.  * The first char of a good data line is the encoded character count for the 
  3191.  * line.  
  3192. d1530 3
  3193. a1532 2
  3194.  * The count INCLUDES the first count char
  3195.  * If the line length is actually 1 + count, then we have a checksum
  3196. d1534 1
  3197. a1534 1
  3198.     expectedLineLen = 4 * ((codingMap[line[0]] + 2) / 3);
  3199. d1536 1
  3200. a1536 1
  3201.     if ((lineLen = strlen(line)) < expectedLineLen)
  3202. d1542 1
  3203. a1542 1
  3204.  * Don't remove all trailing white space!
  3205. d1544 3
  3206. a1546 3
  3207.      for (dataLen = lineLen - 1; 
  3208.           strchr(" \t\n\r",line[dataLen]) && dataLen > 0 && dataLen != expectedLineLen; 
  3209.           dataLen--);
  3210. d1552 1
  3211. d1555 1
  3212. a1555 1
  3213.         if (codingMap[line[i]] == UNUSED)
  3214. d1558 17
  3215. a1579 11
  3216. void
  3217. CreateUUTable()
  3218. {
  3219.     register unsigned int i;
  3220.  
  3221.     for (i=0; i < CODINGTABLESIZE; i++)
  3222.         uuTable[i] = i + 32;
  3223.     
  3224.     uuTable[0] = 96;        /* set space to map to back-quote */    
  3225. }
  3226.  
  3227. a1596 2
  3228.     map[' ']=0;                // decode space to 0
  3229.  
  3230. d1608 1
  3231. a1608 1
  3232. BOOL   
  3233. d1619 1
  3234. a1619 4
  3235.     {
  3236.         dest[0]='\0';
  3237.         return (FAIL);
  3238.     }
  3239. d1622 3
  3240. a1624 2
  3241.         strncpy (dest, threadList[num]->codingTable, CODINGTABLESIZE);
  3242.         return (SUCCESS);
  3243. d1627 13
  3244. a1802 90
  3245. /* ------------------------------------------------------------------------
  3246.  * Check a line to see if it's MIME.  If so, do something intelligent with
  3247.  * it. Note, any MIME header MUST start with 'MIME-version'
  3248.  */
  3249. int
  3250. ParseMimeHeaderLine (TypCoded *thisDecode, char *line)
  3251. {
  3252.         char *ptr;
  3253.  
  3254.     // gotta start with MIME-version, or it ain't MIME
  3255.     if (!bossanovaMIME)            
  3256.         if (!_strnicmp (line, "mime-version", 12))
  3257.         {
  3258.             bossanovaMIME = TRUE;        // hooray
  3259.             return (SUCCESS);
  3260.         }
  3261.         else
  3262.             return (FAIL);
  3263.         
  3264.     if (ParseMimeContentType (thisDecode, line) == SUCCESS)
  3265.         return (SUCCESS);
  3266.         
  3267.     if (!_strnicmp (line, "content-transfer-encoding:", 26))
  3268.     {
  3269.         for (ptr = &line[26]; *ptr && isspace(*ptr); ptr++);
  3270.             if (!_strnicmp (ptr, "x-uue", 5))
  3271.                 thisContentEncoding = ENCODE_UU;
  3272.             else if (!_strnicmp (ptr, "x-xxe", 5))
  3273.                 thisContentEncoding = ENCODE_XX;
  3274.             else if (!_strnicmp (ptr, "base64", 6))
  3275.                 thisContentEncoding = ENCODE_BASE64;
  3276.             else if (!_strnicmp (ptr, "quoted-printable",16))
  3277.                 thisContentEncoding = ENCODE_QP;
  3278.             else
  3279.                 thisContentEncoding = ENCODE_UNKNOWN;
  3280.         return (SUCCESS);
  3281.     }
  3282.     if (!_strnicmp (line, "content-description:", 20))
  3283.     {
  3284.         strcpy (thisContentDesc, &line[20]);
  3285.         return (SUCCESS);
  3286.     }
  3287.     if (!_strnicmp (line, "content-length", 14))
  3288.         return (SUCCESS);
  3289.  
  3290.    return (FAIL);
  3291. }
  3292.  
  3293. int
  3294. ParseMimeContentType (TypCoded *thisDecode, char *line)
  3295. {
  3296.     static int mimeContentLevel = 0;
  3297.     BOOL recurse = FALSE;
  3298.     char *ptr;
  3299.     
  3300.     if (mimeContentLevel == 0)
  3301.         if (!_strnicmp (line, "content-type:", 13))
  3302.         {
  3303.             ptr = strchr (&line[13], ';');    // check for parameters
  3304.             if (*ptr != '\0')
  3305.             {
  3306.                 *ptr = '\0';            // replace ; with \0
  3307.                 if (*(ptr+1) != '\0')
  3308.                     recurse = TRUE;
  3309.             }
  3310.             strcpy (thisContentType, &line[13]);
  3311.             mimeContentLevel++;
  3312.             if (recurse)        // parse same-line parameters
  3313.                 ParseMimeContentType (thisDecode, ptr);
  3314.                 
  3315.             return (SUCCESS);
  3316.         } else
  3317.             return (FAIL);
  3318.     
  3319.     if (!_strnicmp (line, "id=", 3))
  3320.     {
  3321.         ptr = strchr (&line[3], ';');    // check for parameters
  3322.         if (*ptr != '\0')
  3323.         {
  3324.             *ptr = '\0';            // replace ; with \0
  3325.             if (*(ptr+1) != '\0')
  3326.                 recurse = TRUE;
  3327.         }
  3328.         strcpy (thisDecode->ident, &line[3]);
  3329.         if (recurse)        // parse same-line parameters
  3330.             ParseMimeContentType (thisDecode, ptr);
  3331.         return (SUCCESS);
  3332.     }
  3333.     return (FAIL);                
  3334. }
  3335. @
  3336.  
  3337.  
  3338. 1.1
  3339. log
  3340. @Initial revision
  3341. @
  3342. text
  3343. @d38 5
  3344. a42 2
  3345.  * $Id:  $
  3346.  * $Log:  $
  3347. d315 1
  3348. a315 1
  3349.     SetClassWord (hCodedBlockWnd, GCW_HBRBACKGROUND, hStatusBackgroundBrush);
  3350. d389 1
  3351. a389 1
  3352.         hFile = _lopen (fileName, READ);
  3353. d496 1
  3354. a496 1
  3355.     SetClassWord (hCodedBlockWnd, GCW_HBRBACKGROUND, hStatusBackgroundBrush);
  3356. d768 2
  3357. a769 2
  3358.            SetClassWord (threadList[num]->statusText->hTextWnd,
  3359.                  GCW_HBRBACKGROUND, hStatusBackgroundBrush);
  3360. @
  3361.